[MIG][pos_payment_change] from 8.0 to 12.0
- Black python code - OCA Convention - Add tests - add configuration on pos.config, with two option 'refund' or 'update' - The 'refund' option makes the module compatible with (French) certification - make the module compatible with pos_order_returnpull/480/head
-
91pos_change_payment/README.rst
-
6pos_change_payment/__init__.py
-
23pos_change_payment/__openerp__.py
-
168pos_change_payment/i18n/fr.po
-
9pos_change_payment/models/__init__.py
-
66pos_change_payment/models/account_bank_statement_line.py
-
72pos_change_payment/models/pos_change_payments_wizard.py
-
25pos_change_payment/models/pos_change_payments_wizard_line.py
-
25pos_change_payment/models/pos_make_payment.py
-
57pos_change_payment/models/pos_order.py
-
78pos_change_payment/models/pos_switch_journal_wizard.py
-
34pos_change_payment/readme/DESCRIPTION.rst
-
BINpos_change_payment/static/description/icon.png
-
BINpos_change_payment/static/description/pos_order_change_payments.png
-
BINpos_change_payment/static/description/pos_order_switch_payment.png
-
157pos_change_payment/tests/test_module.py
-
26pos_change_payment/views/action.xml
-
21pos_change_payment/views/view_account_bank_statement.xml
-
36pos_change_payment/views/view_pos_change_payments_wizard.xml
-
29pos_change_payment/views/view_pos_switch_journal_wizard.xml
-
8pos_payment_change/README.rst
-
2pos_payment_change/__init__.py
-
20pos_payment_change/__manifest__.py
-
183pos_payment_change/i18n/fr.po
-
2pos_payment_change/models/__init__.py
-
46pos_payment_change/models/pos_config.py
-
82pos_payment_change/models/pos_order.py
-
23pos_payment_change/readme/CONFIGURE.rst
-
0pos_payment_change/readme/CONTRIBUTORS.rst
-
4pos_payment_change/readme/CREDITS.rst
-
6pos_payment_change/readme/DESCRIPTION.rst
-
19pos_payment_change/readme/USAGE.rst
-
BINpos_payment_change/static/description/pos_config_form.png
-
BINpos_payment_change/static/description/pos_order_form.png
-
BINpos_payment_change/static/description/pos_order_tree.png
-
BINpos_payment_change/static/description/pos_payment_change_wizard_form.png
-
1pos_payment_change/tests/__init__.py
-
172pos_payment_change/tests/test_module.py
-
29pos_payment_change/views/view_pos_config.xml
-
15pos_payment_change/views/view_pos_order.xml
-
2pos_payment_change/wizards/__init__.py
-
77pos_payment_change/wizards/pos_payment_change_wizard.py
-
46pos_payment_change/wizards/pos_payment_change_wizard_line.py
-
43pos_payment_change/wizards/view_pos_payment_change_wizard.xml
@ -1,91 +0,0 @@ |
|||||
=============================== |
|
||||
Point Of Sale - Payments Change |
|
||||
=============================== |
|
||||
|
|
||||
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|
||||
!! This file is generated by oca-gen-addon-readme !! |
|
||||
!! changes will be overwritten. !! |
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|
||||
|
|
||||
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png |
|
||||
:target: https://odoo-community.org/page/development-status |
|
||||
:alt: Beta |
|
||||
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png |
|
||||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html |
|
||||
:alt: License: AGPL-3 |
|
||||
.. |badge3| image:: https://img.shields.io/badge/github-grap%2Fgrap--odoo--incubator-lightgray.png?logo=github |
|
||||
:target: https://github.com/grap/grap-odoo-incubator/tree/8.0/pos_change_payment |
|
||||
:alt: grap/grap-odoo-incubator |
|
||||
|
|
||||
|badge1| |badge2| |badge3| |
|
||||
|
|
||||
Improve payment changes when user did a mistake and disable some actions on |
|
||||
Point of Sale Bank Statement Line |
|
||||
|
|
||||
* Add the possibility to switch a payment (account.bank.statement.line) |
|
||||
of an order from a journal to another. This feature is usefull when |
|
||||
the user realized that he did a mistake, during the close of the session, |
|
||||
or just after he marked the order as paid |
|
||||
(Only if entries has not been generated) |
|
||||
|
|
||||
.. figure:: https://raw.githubusercontent.com/grap/grap-odoo-incubator/8.0/pos_change_payment/static/description/pos_order_switch_payment.png |
|
||||
|
|
||||
* Add the possibility to change all payments (method and amount) of a POS |
|
||||
(Only if entries has not been generated) |
|
||||
|
|
||||
.. figure:: https://raw.githubusercontent.com/grap/grap-odoo-incubator/8.0/pos_change_payment/static/description/pos_order_change_payments.png |
|
||||
|
|
||||
Bug Fixes / Improvement |
|
||||
~~~~~~~~~~~~~~~~~~~~~~~ |
|
||||
|
|
||||
* In the pos.payment wizard, display only the payment methods defined in |
|
||||
the current POS session |
|
||||
|
|
||||
* Disable the possibility to edit / delete a bank statement line on a POS |
|
||||
Order that has generated his entries, except using the wizard of this |
|
||||
module. This will prevent the generation of bad account move during |
|
||||
the close of the session; (mainly unbalanced moves) |
|
||||
|
|
||||
* All the cash payment are merged into a single one statement line. This |
|
||||
feature is usefull if the user use OpenERP as a calculator, writing |
|
||||
for a payment: |
|
||||
|
|
||||
1. Payment 1/ Cash 50 €; |
|
||||
2. Payment 2/ Cash -3,56 €; |
|
||||
3. With this module, the final statement line is a single line Payment 1/ Cash 46,44 € |
|
||||
|
|
||||
**Table of contents** |
|
||||
|
|
||||
.. contents:: |
|
||||
:local: |
|
||||
|
|
||||
Bug Tracker |
|
||||
=========== |
|
||||
|
|
||||
Bugs are tracked on `GitHub Issues <https://github.com/grap/grap-odoo-incubator/issues>`_. |
|
||||
In case of trouble, please check there if your issue has already been reported. |
|
||||
If you spotted it first, help us smashing it by providing a detailed and welcomed |
|
||||
`feedback <https://github.com/grap/grap-odoo-incubator/issues/new?body=module:%20pos_change_payment%0Aversion:%208.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. |
|
||||
|
|
||||
Do not contact contributors directly about support or help with technical issues. |
|
||||
|
|
||||
Credits |
|
||||
======= |
|
||||
|
|
||||
Authors |
|
||||
~~~~~~~ |
|
||||
|
|
||||
* GRAP |
|
||||
|
|
||||
Contributors |
|
||||
~~~~~~~~~~~~ |
|
||||
|
|
||||
* Sylvain LE GAL <https://twitter.com/legalsylvain> |
|
||||
* Julien WESTE |
|
||||
|
|
||||
Maintainers |
|
||||
~~~~~~~~~~~ |
|
||||
|
|
||||
This module is part of the `grap/grap-odoo-incubator <https://github.com/grap/grap-odoo-incubator/tree/8.0/pos_change_payment>`_ project on GitHub. |
|
||||
|
|
||||
You are welcome to contribute. |
|
@ -1,6 +0,0 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
# Copyright (C) 2015-Today GRAP (http://www.grap.coop) |
|
||||
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
|
|
||||
from . import models |
|
@ -1,23 +0,0 @@ |
|||||
# coding: utf-8 |
|
||||
# Copyright (C) 2013 - Today: GRAP (http://www.grap.coop) |
|
||||
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
{ |
|
||||
'name': 'Point Of Sale - Payments Change', |
|
||||
'version': '8.0.1.0.0', |
|
||||
'category': 'Point Of Sale', |
|
||||
'author': 'GRAP', |
|
||||
'website': 'http://www.grap.coop', |
|
||||
'license': 'AGPL-3', |
|
||||
'depends': [ |
|
||||
'point_of_sale', |
|
||||
], |
|
||||
'data': [ |
|
||||
'views/action.xml', |
|
||||
'views/view_account_bank_statement.xml', |
|
||||
'views/view_pos_change_payments_wizard.xml', |
|
||||
'views/view_pos_order.xml', |
|
||||
'views/view_pos_switch_journal_wizard.xml', |
|
||||
], |
|
||||
'installable': True, |
|
||||
} |
|
@ -1,168 +0,0 @@ |
|||||
# Translation of OpenERP Server. |
|
||||
# This file contains the translation of the following modules: |
|
||||
# * pos_change_payment |
|
||||
# |
|
||||
msgid "" |
|
||||
msgstr "" |
|
||||
"Project-Id-Version: OpenERP Server 7.0\n" |
|
||||
"Report-Msgid-Bugs-To: \n" |
|
||||
"POT-Creation-Date: 2015-04-01 14:25+0000\n" |
|
||||
"PO-Revision-Date: 2015-04-01 14:25+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: pos_change_payment |
|
||||
#: field:pos.change.payments.wizard.line,amount:0 |
|
||||
#: field:pos.switch.journal.wizard,amount:0 |
|
||||
msgid "Amount" |
|
||||
msgstr "Montant" |
|
||||
|
|
||||
#. module: pos_change_payment |
|
||||
#: code:_description:0 |
|
||||
#: model:ir.model,name:pos_change_payment.model_account_bank_statement_line |
|
||||
#, python-format |
|
||||
msgid "Bank Statement Line" |
|
||||
msgstr "Ligne de relevé de banque" |
|
||||
|
|
||||
#. module: pos_change_payment |
|
||||
#: view:pos.change.payments.wizard:0 |
|
||||
#: view:pos.switch.journal.wizard:0 |
|
||||
msgid "Cancel" |
|
||||
msgstr "Annuler" |
|
||||
|
|
||||
#. module: pos_change_payment |
|
||||
#: model:ir.actions.act_window,name:pos_change_payment.action_pos_change_payments_wizard |
|
||||
#: view:pos.change.payments.wizard:0 |
|
||||
#: view:pos.order:0 |
|
||||
msgid "Change Payments" |
|
||||
msgstr "Changer les paiements" |
|
||||
|
|
||||
#. module: pos_change_payment |
|
||||
#: code:addons/pos_change_payment/model/pos_change_payments_wizard.py:77 |
|
||||
#, python-format |
|
||||
msgid "Differences between the two values for the POS Order '%s':\n" |
|
||||
"\n" |
|
||||
" * Total of all the new payments %s;\n" |
|
||||
" * Total of the POS Order %s;\n" |
|
||||
"\n" |
|
||||
"Please change the payments." |
|
||||
msgstr "Différences entre les deux valeurs pour la vente '%s':\n" |
|
||||
"\n" |
|
||||
" * Total des nouveaux paiements %s;\n" |
|
||||
" * Total de la vente %s;\n" |
|
||||
"\n" |
|
||||
"Veuillez changer les paiements." |
|
||||
|
|
||||
#. module: pos_change_payment |
|
||||
#: code:addons/pos_change_payment/model/account_bank_statement_line.py:78 |
|
||||
#: code:addons/pos_change_payment/model/pos_change_payments_wizard.py:36 |
|
||||
#: code:addons/pos_change_payment/model/pos_change_payments_wizard.py:72 |
|
||||
#: code:addons/pos_change_payment/model/pos_order.py:76 |
|
||||
#: code:addons/pos_change_payment/model/pos_switch_journal_wizard.py:64 |
|
||||
#, python-format |
|
||||
msgid "Error!" |
|
||||
msgstr "Erreur !" |
|
||||
|
|
||||
#. module: pos_change_payment |
|
||||
#: code:addons/pos_change_payment/model/pos_change_payments_wizard.py:36 |
|
||||
#: code:addons/pos_change_payment/model/pos_switch_journal_wizard.py:64 |
|
||||
#, python-format |
|
||||
msgid "Incorrect Call!" |
|
||||
msgstr "Appel incorrect !" |
|
||||
|
|
||||
#. module: pos_change_payment |
|
||||
#: code:_description:0 |
|
||||
#: model:ir.model,name:pos_change_payment.model_account_journal |
|
||||
#: field:pos.change.payments.wizard.line,journal_id:0 |
|
||||
#, python-format |
|
||||
msgid "Journal" |
|
||||
msgstr "Journal" |
|
||||
|
|
||||
#. module: pos_change_payment |
|
||||
#: field:pos.switch.journal.wizard,new_statement_id:0 |
|
||||
msgid "New Journal" |
|
||||
msgstr "Nouveau journal" |
|
||||
|
|
||||
#. module: pos_change_payment |
|
||||
#: field:pos.switch.journal.wizard,old_journal_id:0 |
|
||||
msgid "Old Journal" |
|
||||
msgstr "Ancien journal" |
|
||||
|
|
||||
#. module: pos_change_payment |
|
||||
#: field:pos.change.payments.wizard,order_id:0 |
|
||||
msgid "POS Order" |
|
||||
msgstr "Vente" |
|
||||
|
|
||||
#. module: pos_change_payment |
|
||||
#: view:pos.order:0 |
|
||||
msgid "Payment" |
|
||||
msgstr "Paiement" |
|
||||
|
|
||||
#. module: pos_change_payment |
|
||||
#: view:pos.change.payments.wizard:0 |
|
||||
msgid "Payment Lines" |
|
||||
msgstr "Lignes de paiement" |
|
||||
|
|
||||
#. module: pos_change_payment |
|
||||
#: code:_description:0 |
|
||||
#: model:ir.model,name:pos_change_payment.model_pos_order |
|
||||
#, python-format |
|
||||
msgid "Point of Sale" |
|
||||
msgstr "Point de Vente" |
|
||||
|
|
||||
#. module: pos_change_payment |
|
||||
#: code:_description:0 |
|
||||
#: model:ir.model,name:pos_change_payment.model_pos_make_payment |
|
||||
#, python-format |
|
||||
msgid "Point of Sale Payment" |
|
||||
msgstr "Paiement du ticket" |
|
||||
|
|
||||
#. module: pos_change_payment |
|
||||
#: field:pos.switch.journal.wizard,statement_line_id:0 |
|
||||
msgid "Statement" |
|
||||
msgstr "Relevé bancaire" |
|
||||
|
|
||||
#. module: pos_change_payment |
|
||||
#: view:account.bank.statement:0 |
|
||||
#: model:ir.actions.act_window,name:pos_change_payment.action_pos_switch_journal_wizard |
|
||||
#: view:pos.order:0 |
|
||||
#: view:pos.switch.journal.wizard:0 |
|
||||
msgid "Switch Journal" |
|
||||
msgstr "Changer de Journal" |
|
||||
|
|
||||
#. module: pos_change_payment |
|
||||
#: field:pos.change.payments.wizard,amount_total:0 |
|
||||
msgid "Total" |
|
||||
msgstr "Total" |
|
||||
|
|
||||
#. module: pos_change_payment |
|
||||
#: field:pos.change.payments.wizard,line_ids:0 |
|
||||
msgid "Wizard Lines" |
|
||||
msgstr "Lignes" |
|
||||
|
|
||||
#. module: pos_change_payment |
|
||||
#: field:pos.change.payments.wizard.line,wizard_id:0 |
|
||||
msgid "Wizard Ref" |
|
||||
msgstr "Référence" |
|
||||
|
|
||||
#. module: pos_change_payment |
|
||||
#: code:addons/pos_change_payment/model/account_bank_statement_line.py:79 |
|
||||
#, python-format |
|
||||
msgid "You can not change payments of POS by this way. Please use the regular wizard in POS view!" |
|
||||
msgstr "Vous ne pouvez pas changer les paiements de cette vente de cette façon. Veuillez utiliser l'interface prévue à cet effet dans la vue de la vente !" |
|
||||
|
|
||||
#. module: pos_change_payment |
|
||||
#: code:addons/pos_change_payment/model/pos_order.py:78 |
|
||||
#, python-format |
|
||||
msgid "You can not change payments of the POS '%s' because the associated session '%s' has been closed!" |
|
||||
msgstr "Vous ne pouvez pas changer les paiements de la Vente '%s' car la session associée '%s' a été clôturé !" |
|
||||
|
|
||||
#. module: pos_change_payment |
|
||||
#: view:pos.change.payments.wizard:0 |
|
||||
#: view:pos.switch.journal.wizard:0 |
|
||||
msgid "or" |
|
||||
msgstr "ou" |
|
@ -1,9 +0,0 @@ |
|||||
# coding: utf-8 |
|
||||
|
|
||||
from . import pos_order |
|
||||
from . import account_bank_statement_line |
|
||||
from . import pos_make_payment |
|
||||
|
|
||||
from . import pos_switch_journal_wizard |
|
||||
from . import pos_change_payments_wizard |
|
||||
from . import pos_change_payments_wizard_line |
|
@ -1,66 +0,0 @@ |
|||||
# coding: utf-8 |
|
||||
# Copyright (C) 2015-Today GRAP (http://www.grap.coop) |
|
||||
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
|
|
||||
|
|
||||
from openerp import _, api, models |
|
||||
from openerp.exceptions import ValidationError |
|
||||
|
|
||||
|
|
||||
class AccountBankStatementLine(models.Model): |
|
||||
_inherit = 'account.bank.statement.line' |
|
||||
|
|
||||
_POS_PAYMENT_ALLOW_WRITE = [ |
|
||||
'sequence', 'journal_entry_id', |
|
||||
] |
|
||||
|
|
||||
# Private Function Section |
|
||||
@api.multi |
|
||||
def _check_allow_change_pos_payment(self, vals): |
|
||||
"""Allow or block change of account bank statement line, linked to |
|
||||
a non draft POS Order. |
|
||||
* if 'change_pos_payment' is in the context, changes are allowed; |
|
||||
* otherwise: |
|
||||
* allow write of some fields only; |
|
||||
* forbid deletion;""" |
|
||||
values = vals.copy() if vals else {} |
|
||||
check_pos_order = False |
|
||||
|
|
||||
if values: |
|
||||
# Allow some write |
|
||||
for key in self._POS_PAYMENT_ALLOW_WRITE: |
|
||||
if key in values: |
|
||||
del values[key] |
|
||||
if not values: |
|
||||
return |
|
||||
|
|
||||
# Allow changes, if user use the wizard |
|
||||
if self._context.get('change_pos_payment', False): |
|
||||
check_pos_order = True |
|
||||
|
|
||||
for statement_line in self: |
|
||||
order = statement_line.pos_statement_id |
|
||||
if order: |
|
||||
if order.state != 'draft': |
|
||||
if check_pos_order: |
|
||||
order._allow_change_payments() |
|
||||
else: |
|
||||
if values.keys() == ['partner_id']: |
|
||||
order._allow_change_payments() |
|
||||
else: |
|
||||
raise ValidationError(_( |
|
||||
"You can not change payments of POS by this" |
|
||||
" way. Please use the regular wizard in POS" |
|
||||
" view!")) |
|
||||
|
|
||||
# Overload Section |
|
||||
@api.multi |
|
||||
def write(self, vals): |
|
||||
self._check_allow_change_pos_payment(vals) |
|
||||
return super(AccountBankStatementLine, self).write(vals) |
|
||||
|
|
||||
@api.multi |
|
||||
def unlink(self): |
|
||||
self._check_allow_change_pos_payment(None) |
|
||||
return super(AccountBankStatementLine, self).unlink() |
|
@ -1,72 +0,0 @@ |
|||||
# coding: utf-8 |
|
||||
# Copyright (C) 2015-Today GRAP (http://www.grap.coop) |
|
||||
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
|
|
||||
from openerp import _, api, fields, models |
|
||||
from openerp.exceptions import Warning as UserError |
|
||||
|
|
||||
|
|
||||
class PosChangePaymentsWizard(models.TransientModel): |
|
||||
_name = 'pos.change.payments.wizard' |
|
||||
|
|
||||
# Column Section |
|
||||
order_id = fields.Many2one( |
|
||||
comodel_name='pos.order', string='Order', readonly=True) |
|
||||
|
|
||||
session_id = fields.Many2one( |
|
||||
comodel_name='pos.session', string='Session', readonly=True) |
|
||||
|
|
||||
line_ids = fields.One2many( |
|
||||
comodel_name='pos.change.payments.wizard.line', |
|
||||
inverse_name='wizard_id', string='Payment Lines') |
|
||||
|
|
||||
amount_total = fields.Float(string='Total', readonly=True) |
|
||||
|
|
||||
# View Section |
|
||||
@api.model |
|
||||
def default_get(self, fields): |
|
||||
order_obj = self.env['pos.order'] |
|
||||
res = super(PosChangePaymentsWizard, self).default_get(fields) |
|
||||
order = order_obj.browse(self._context.get('active_id')) |
|
||||
res.update({'order_id': order.id}) |
|
||||
res.update({'session_id': order.session_id.id}) |
|
||||
res.update({'amount_total': order.amount_total}) |
|
||||
return res |
|
||||
|
|
||||
# View section |
|
||||
@api.multi |
|
||||
def button_change_payments(self): |
|
||||
self.ensure_one() |
|
||||
order = self.order_id |
|
||||
|
|
||||
# Check if the total is correct |
|
||||
total = 0 |
|
||||
for line in self.line_ids: |
|
||||
total += line.amount |
|
||||
if total != self.amount_total: |
|
||||
raise UserError(_( |
|
||||
"Differences between the two values for the POS" |
|
||||
" Order '%s':\n\n" |
|
||||
" * Total of all the new payments %s;\n" |
|
||||
" * Total of the POS Order %s;\n\n" |
|
||||
"Please change the payments." % ( |
|
||||
order.name, total, order.amount_total))) |
|
||||
|
|
||||
# Check if change payments is allowed |
|
||||
order._allow_change_payments() |
|
||||
|
|
||||
# Remove old statements |
|
||||
order.statement_ids.with_context(change_pos_payment=True).unlink() |
|
||||
|
|
||||
# Create new payment |
|
||||
for line in self.line_ids: |
|
||||
order.add_payment_v8({ |
|
||||
'journal': line.new_journal_id.id, |
|
||||
'amount': line.amount, |
|
||||
}) |
|
||||
|
|
||||
return { |
|
||||
'type': 'ir.actions.client', |
|
||||
'tag': 'reload', |
|
||||
} |
|
@ -1,25 +0,0 @@ |
|||||
# coding: utf-8 |
|
||||
# Copyright (C) 2015 - Today: GRAP (http://www.grap.coop) |
|
||||
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
|
|
||||
from openerp import api, fields, models |
|
||||
|
|
||||
|
|
||||
class PosChangePaymentsWizardLine(models.TransientModel): |
|
||||
_name = 'pos.change.payments.wizard.line' |
|
||||
|
|
||||
wizard_id = fields.Many2one( |
|
||||
comodel_name='pos.change.payments.wizard', ondelete='cascade') |
|
||||
|
|
||||
new_journal_id = fields.Many2one( |
|
||||
comodel_name='account.journal', string='Journal', required=True, |
|
||||
domain=lambda s: s._domain_new_journal_id()) |
|
||||
|
|
||||
amount = fields.Float(string='Amount', required=True) |
|
||||
|
|
||||
@api.model |
|
||||
def _domain_new_journal_id(self): |
|
||||
PosOrder = self.env['pos.order'] |
|
||||
order = PosOrder.browse(self.env.context.get('active_id')) |
|
||||
return [('id', 'in', order.session_id.journal_ids.ids)] |
|
@ -1,25 +0,0 @@ |
|||||
# coding: utf-8 |
|
||||
# Copyright (C) 2015-Today GRAP (http://www.grap.coop) |
|
||||
# @author Julien WESTE |
|
||||
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
|
|
||||
from openerp import api, models, fields |
|
||||
|
|
||||
|
|
||||
class PosMakePayment(models.TransientModel): |
|
||||
_inherit = 'pos.make.payment' |
|
||||
|
|
||||
# # Column Section (Overload) |
|
||||
journal_id = fields.Many2one( |
|
||||
default=False, |
|
||||
domain=lambda s: s._domain_journal_id()) |
|
||||
|
|
||||
@api.model |
|
||||
def _domain_journal_id(self): |
|
||||
session_obj = self.env['pos.session'] |
|
||||
if self.env.context.get('pos_session_id', False): |
|
||||
session = session_obj.browse( |
|
||||
int(self._context.get('pos_session_id'))) |
|
||||
return [('id', 'in', session.journal_ids.ids)] |
|
||||
return [] |
|
@ -1,57 +0,0 @@ |
|||||
# coding: utf-8 |
|
||||
# Copyright (C) 2015 - Today: GRAP (http://www.grap.coop) |
|
||||
# @author: Julien WESTE |
|
||||
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
|
|
||||
from openerp import _, api, models |
|
||||
from openerp.exceptions import Warning as UserError |
|
||||
|
|
||||
|
|
||||
class PosOrder(models.Model): |
|
||||
_inherit = 'pos.order' |
|
||||
|
|
||||
# Overload Section |
|
||||
@api.multi |
|
||||
def action_paid(self): |
|
||||
""" Merge all cash statement line of the Order""" |
|
||||
self._merge_cash_payment() |
|
||||
return super(PosOrder, self).action_paid() |
|
||||
|
|
||||
@api.multi |
|
||||
def add_payment_v8(self, data): |
|
||||
"""Hack to call old api. TODO-V10 : remove me.""" |
|
||||
for order in self: |
|
||||
self.pool['pos.order'].add_payment( |
|
||||
self._cr, self._uid, order.id, data, context=self._context) |
|
||||
return True |
|
||||
|
|
||||
# Private Function Section |
|
||||
@api.multi |
|
||||
def _merge_cash_payment(self): |
|
||||
for order in self: |
|
||||
cash_statements = order.statement_ids.filtered( |
|
||||
lambda x: x.journal_id.type == 'cash') |
|
||||
if len(cash_statements) < 2: |
|
||||
continue |
|
||||
|
|
||||
main_statement = cash_statements[0] |
|
||||
cash_total = sum(cash_statements.mapped('amount')) |
|
||||
|
|
||||
# Unlink all statements except one |
|
||||
cash_statements.filtered( |
|
||||
lambda x: x.id != main_statement.id).unlink() |
|
||||
main_statement.write({'amount': cash_total}) |
|
||||
|
|
||||
@api.multi |
|
||||
def _allow_change_payments(self): |
|
||||
"""Return True if the user can change the payment of a POS, depending |
|
||||
of the state of the current session.""" |
|
||||
closed_orders = self.filtered( |
|
||||
lambda x: x.session_id.state == 'closed') |
|
||||
if len(closed_orders): |
|
||||
raise UserError(_( |
|
||||
"You can not change payments of the POS '%s' because" |
|
||||
" the associated session '%s' has been closed!" % ( |
|
||||
', '.join(closed_orders.mapped('name')), |
|
||||
', '.join(closed_orders.mapped('session_id.name'))))) |
|
@ -1,78 +0,0 @@ |
|||||
# coding: utf-8 |
|
||||
# Copyright (C) 2015 - Today: GRAP (http://www.grap.coop) |
|
||||
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
|
|
||||
from openerp import api, fields, models |
|
||||
|
|
||||
|
|
||||
class PosSwitchJournalWizard(models.TransientModel): |
|
||||
_name = 'pos.switch.journal.wizard' |
|
||||
|
|
||||
order_id = fields.Many2one( |
|
||||
comodel_name='pos.order', string='PoS Order', |
|
||||
required=True, readonly=True) |
|
||||
|
|
||||
statement_line_id = fields.Many2one( |
|
||||
comodel_name='account.bank.statement.line', string='Statement', |
|
||||
required=True, readonly=True) |
|
||||
|
|
||||
old_journal_id = fields.Many2one( |
|
||||
comodel_name='account.journal', string='Old Journal', |
|
||||
required=True, readonly=True) |
|
||||
|
|
||||
new_journal_id = fields.Many2one( |
|
||||
comodel_name='account.journal', string='New Journal', |
|
||||
required=True, domain=lambda s: s._domain_new_journal_id()) |
|
||||
|
|
||||
amount = fields.Float(string='Amount', readonly=True) |
|
||||
|
|
||||
@api.model |
|
||||
def _domain_new_journal_id(self): |
|
||||
AccountBankStatementLine = self.env['account.bank.statement.line'] |
|
||||
statement_line = AccountBankStatementLine.browse( |
|
||||
self.env.context.get('active_id')) |
|
||||
return [( |
|
||||
'id', 'in', |
|
||||
statement_line.pos_statement_id.session_id.journal_ids.ids)] |
|
||||
|
|
||||
@api.model |
|
||||
def default_get(self, fields): |
|
||||
AccountBankStatementLine = self.env['account.bank.statement.line'] |
|
||||
res = super(PosSwitchJournalWizard, self).default_get(fields) |
|
||||
statement_line = AccountBankStatementLine.browse( |
|
||||
self.env.context.get('active_id')) |
|
||||
res.update({'statement_line_id': statement_line.id}) |
|
||||
res.update({'order_id': statement_line.pos_statement_id.id}) |
|
||||
res.update({'old_journal_id': statement_line.journal_id.id}) |
|
||||
res.update({'amount': statement_line.amount}) |
|
||||
return res |
|
||||
|
|
||||
# Action section |
|
||||
@api.multi |
|
||||
def button_switch_journal(self): |
|
||||
self.ensure_one() |
|
||||
# Check if changing payment is allowed |
|
||||
self.order_id._allow_change_payments() |
|
||||
|
|
||||
# TODO (FIXME) when upstream is fixed. |
|
||||
# We do 2 write, one in the old statement, one in the new, with |
|
||||
# 'amount' value each time to recompute all the functional fields |
|
||||
# of the Account Bank Statements |
|
||||
amount = self.amount |
|
||||
self.statement_line_id.with_context(change_pos_payment=True).write({ |
|
||||
'amount': 0.0, |
|
||||
}) |
|
||||
|
|
||||
# Change statement of the statement line |
|
||||
new_statement = self.order_id.session_id.statement_ids.filtered( |
|
||||
lambda x: x.journal_id == self.new_journal_id)[0] |
|
||||
self.statement_line_id.with_context(change_pos_payment=True).write({ |
|
||||
'amount': amount, |
|
||||
'statement_id': new_statement.id, |
|
||||
}) |
|
||||
|
|
||||
return { |
|
||||
'type': 'ir.actions.client', |
|
||||
'tag': 'reload', |
|
||||
} |
|
@ -1,34 +0,0 @@ |
|||||
Improve payment changes when user did a mistake and disable some actions on |
|
||||
Point of Sale Bank Statement Line |
|
||||
|
|
||||
* Add the possibility to switch a payment (account.bank.statement.line) |
|
||||
of an order from a journal to another. This feature is usefull when |
|
||||
the user realized that he did a mistake, during the close of the session, |
|
||||
or just after he marked the order as paid |
|
||||
(Only if entries has not been generated) |
|
||||
|
|
||||
.. figure:: ../static/description/pos_order_switch_payment.png |
|
||||
|
|
||||
* Add the possibility to change all payments (method and amount) of a POS |
|
||||
(Only if entries has not been generated) |
|
||||
|
|
||||
.. figure:: ../static/description/pos_order_change_payments.png |
|
||||
|
|
||||
Bug Fixes / Improvement |
|
||||
~~~~~~~~~~~~~~~~~~~~~~~ |
|
||||
|
|
||||
* In the pos.payment wizard, display only the payment methods defined in |
|
||||
the current POS session |
|
||||
|
|
||||
* Disable the possibility to edit / delete a bank statement line on a POS |
|
||||
Order that has generated his entries, except using the wizard of this |
|
||||
module. This will prevent the generation of bad account move during |
|
||||
the close of the session; (mainly unbalanced moves) |
|
||||
|
|
||||
* All the cash payment are merged into a single one statement line. This |
|
||||
feature is usefull if the user use OpenERP as a calculator, writing |
|
||||
for a payment: |
|
||||
|
|
||||
1. Payment 1/ Cash 50 €; |
|
||||
2. Payment 2/ Cash -3,56 €; |
|
||||
3. With this module, the final statement line is a single line Payment 1/ Cash 46,44 € |
|
Before Width: 128 | Height: 128 | Size: 8.6 KiB |
Before Width: 892 | Height: 435 | Size: 28 KiB |
Before Width: 890 | Height: 199 | Size: 26 KiB |
@ -1,157 +0,0 @@ |
|||||
# coding: utf-8 |
|
||||
# Copyright (C) 2018 - Today: GRAP (http://www.grap.coop) |
|
||||
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
|
|
||||
from openerp.tests.common import TransactionCase |
|
||||
from openerp.exceptions import Warning as UserError |
|
||||
|
|
||||
|
|
||||
class TestModule(TransactionCase): |
|
||||
"""Tests for 'Point of Sale - Change Payment' Module""" |
|
||||
|
|
||||
def setUp(self): |
|
||||
super(TestModule, self).setUp() |
|
||||
self.PosSession = self.env['pos.session'] |
|
||||
self.PosOrder = self.env['pos.order'] |
|
||||
self.PosMakePayment = self.env['pos.make.payment'] |
|
||||
self.PosSwitchJournalWizard = self.env['pos.switch.journal.wizard'] |
|
||||
self.PosChangePaymentsWizard = self.env['pos.change.payments.wizard'] |
|
||||
self.PosChangePaymentsWizardLine =\ |
|
||||
self.env['pos.change.payments.wizard.line'] |
|
||||
self.product = self.env.ref('product.product_product_3') |
|
||||
self.pos_config = self.env.ref('point_of_sale.pos_config_main') |
|
||||
self.check_journal = self.env.ref('account.check_journal') |
|
||||
self.cash_journal = self.env.ref('account.cash_journal') |
|
||||
|
|
||||
# create new session and open it |
|
||||
self.session = self.PosSession.create( |
|
||||
{'config_id': self.pos_config.id}) |
|
||||
self.session.open_cb() |
|
||||
self.check_statement = self.session.statement_ids.filtered( |
|
||||
lambda x: x.journal_id == self.check_journal) |
|
||||
self.cash_statement = self.session.statement_ids.filtered( |
|
||||
lambda x: x.journal_id == self.cash_journal) |
|
||||
|
|
||||
def _sale(self, session, journal_1, price_1, journal_2=False, price_2=0.0): |
|
||||
order = self.PosOrder.create({ |
|
||||
'session_id': session.id, |
|
||||
'lines': [[0, False, { |
|
||||
'name': 'OL/0001', |
|
||||
'product_id': self.product.id, |
|
||||
'qty': 1.0, |
|
||||
'price_unit': price_1 + price_2, |
|
||||
}]], |
|
||||
}) |
|
||||
payment = self.PosMakePayment.with_context(active_id=order.id).create({ |
|
||||
'journal_id': journal_1.id, |
|
||||
'amount': price_1, |
|
||||
}) |
|
||||
payment.with_context(active_id=order.id).check() |
|
||||
if journal_2: |
|
||||
payment = self.PosMakePayment.with_context( |
|
||||
active_id=order.id).create({ |
|
||||
'journal_id': journal_2.id, |
|
||||
'amount': price_2, |
|
||||
}) |
|
||||
payment.with_context(active_id=order.id).check() |
|
||||
return order |
|
||||
|
|
||||
# Test Section |
|
||||
def test_01_pos_switch_journal(self): |
|
||||
# Make a sale with 100 in cash journal |
|
||||
order = self._sale(self.session, self.cash_journal, 100) |
|
||||
statement_line = order.statement_ids[0] |
|
||||
|
|
||||
# Switch to check journal |
|
||||
wizard = self.PosSwitchJournalWizard.with_context( |
|
||||
active_id=statement_line.id).create({ |
|
||||
'new_journal_id': self.check_journal.id, |
|
||||
}) |
|
||||
wizard.button_switch_journal() |
|
||||
|
|
||||
# Check Order |
|
||||
self.assertEqual( |
|
||||
len(order.statement_ids.filtered( |
|
||||
lambda x: x.journal_id == self.cash_journal)), 0, |
|
||||
"Altered order should not have the original payment journal") |
|
||||
|
|
||||
self.assertEqual( |
|
||||
len(order.statement_ids.filtered( |
|
||||
lambda x: x.journal_id == self.check_journal)), 1, |
|
||||
"Altered order should have the final payment journal") |
|
||||
|
|
||||
# Check Session |
|
||||
self.assertEqual( |
|
||||
self.cash_statement.balance_end, 0, |
|
||||
"Bad recompute of the balance for the old statement") |
|
||||
|
|
||||
self.assertEqual( |
|
||||
self.check_statement.balance_end, 100, |
|
||||
"Bad recompute of the balance for the new statement") |
|
||||
|
|
||||
def test_02_pos_change_payment(self): |
|
||||
# Make a sale with 35 in cash journal and 65 in check |
|
||||
order = self._sale( |
|
||||
self.session, self.cash_journal, 35, self.check_journal, 65) |
|
||||
|
|
||||
# Switch to check journal |
|
||||
wizard = self.PosChangePaymentsWizard.with_context( |
|
||||
active_id=order.id).create({}) |
|
||||
self.PosChangePaymentsWizardLine.with_context( |
|
||||
active_id=order.id).create({ |
|
||||
'wizard_id': wizard.id, |
|
||||
'new_journal_id': self.cash_journal.id, |
|
||||
'amount': 10, |
|
||||
}) |
|
||||
self.PosChangePaymentsWizardLine.with_context( |
|
||||
active_id=order.id).create({ |
|
||||
'wizard_id': wizard.id, |
|
||||
'new_journal_id': self.check_journal.id, |
|
||||
'amount': 40, |
|
||||
}) |
|
||||
|
|
||||
with self.assertRaises(UserError): |
|
||||
# Should not work if total is not correct |
|
||||
wizard.button_change_payments() |
|
||||
|
|
||||
# Finish payement |
|
||||
self.PosChangePaymentsWizardLine.with_context( |
|
||||
active_id=order.id).create({ |
|
||||
'wizard_id': wizard.id, |
|
||||
'new_journal_id': self.check_journal.id, |
|
||||
'amount': 50, |
|
||||
}) |
|
||||
wizard.button_change_payments() |
|
||||
|
|
||||
# check Session |
|
||||
self.assertEqual( |
|
||||
self.cash_statement.balance_end, 10, |
|
||||
"Bad recompute of the balance for the old statement") |
|
||||
|
|
||||
self.assertEqual( |
|
||||
self.check_statement.balance_end, 90, |
|
||||
"Bad recompute of the balance for the new statement") |
|
||||
|
|
||||
def test_03_merge_statement(self): |
|
||||
# Make a sale with multiple cash payement |
|
||||
order = self._sale( |
|
||||
self.session, self.cash_journal, 100, |
|
||||
journal_2=self.cash_journal, price_2=200) |
|
||||
# Check that statement has been merged |
|
||||
self.assertEqual( |
|
||||
len(order.statement_ids), 1, |
|
||||
"Adding many cash statement for an order should merge them.") |
|
||||
|
|
||||
self.assertEqual( |
|
||||
order.statement_ids[0].amount, 300, |
|
||||
"Invalid total amount for merged cash statements") |
|
||||
|
|
||||
# Make a sale with multiple check payement |
|
||||
order = self._sale( |
|
||||
self.session, self.check_journal, 100, |
|
||||
self.check_journal, 200) |
|
||||
# Check that statement has been merged |
|
||||
self.assertEqual( |
|
||||
len(order.statement_ids), 2, |
|
||||
"Adding many check statement for an order should not merge them.") |
|
@ -1,26 +0,0 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
|
||||
<!-- |
|
||||
Copyright (C) 2015-Today GRAP (http://www.grap.coop) |
|
||||
@author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
--> |
|
||||
|
|
||||
<openerp><data> |
|
||||
|
|
||||
<record id="action_pos_switch_journal_wizard" model="ir.actions.act_window"> |
|
||||
<field name="name">Switch Journal</field> |
|
||||
<field name="res_model">pos.switch.journal.wizard</field> |
|
||||
<field name="view_type">form</field> |
|
||||
<field name="view_mode">form</field> |
|
||||
<field name="target">new</field> |
|
||||
</record> |
|
||||
|
|
||||
<record id="action_pos_change_payments_wizard" model="ir.actions.act_window"> |
|
||||
<field name="name">Change Payments</field> |
|
||||
<field name="res_model">pos.change.payments.wizard</field> |
|
||||
<field name="view_type">form</field> |
|
||||
<field name="view_mode">form</field> |
|
||||
<field name="target">new</field> |
|
||||
</record> |
|
||||
|
|
||||
</data></openerp> |
|
@ -1,21 +0,0 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
|
||||
<!-- |
|
||||
Copyright (C) 2015-Today GRAP (http://www.grap.coop) |
|
||||
@author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
--> |
|
||||
|
|
||||
<openerp><data> |
|
||||
|
|
||||
<record id="view_account_bank_statement_form" model="ir.ui.view"> |
|
||||
<field name="model">account.bank.statement</field> |
|
||||
<field name="inherit_id" ref="account.view_bank_statement_form" /> |
|
||||
<field name="arch" type="xml"> |
|
||||
<xpath expr="//field[@name='line_ids']/tree/field[@name='amount']" position="after"> |
|
||||
<field name="pos_statement_id" invisible="1" /> |
|
||||
<button name="%(action_pos_switch_journal_wizard)d" string="Switch Journal" type="action" icon="gtk-index" attrs="{'invisible':[('pos_statement_id', '=', False)]}"/> |
|
||||
</xpath> |
|
||||
</field> |
|
||||
</record> |
|
||||
|
|
||||
</data></openerp> |
|
@ -1,36 +0,0 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
|
||||
<!-- |
|
||||
Copyright (C) 2015-Today GRAP (http://www.grap.coop) |
|
||||
@author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
--> |
|
||||
|
|
||||
<openerp><data> |
|
||||
|
|
||||
<record id="view_pos_change_payments_wizard_form" model="ir.ui.view"> |
|
||||
<field name="model">pos.change.payments.wizard</field> |
|
||||
<field name="arch" type="xml"> |
|
||||
<form> |
|
||||
<group col="4"> |
|
||||
<field name="order_id" /> |
|
||||
<field name="session_id" /> |
|
||||
<field name="amount_total" /> |
|
||||
<newline /> |
|
||||
<field name="line_ids" colspan="4"> |
|
||||
<tree string="Payment Lines" editable="bottom"> |
|
||||
<field name="new_journal_id" widget="selection"/> |
|
||||
<field name="amount" /> |
|
||||
</tree> |
|
||||
</field> |
|
||||
</group> |
|
||||
<footer> |
|
||||
<button name="button_change_payments" string="Change Payments" |
|
||||
type="object" class="oe_highlight"/> |
|
||||
<label string="or" /> |
|
||||
<button string="Cancel" class="oe_link" special="cancel" /> |
|
||||
</footer> |
|
||||
</form> |
|
||||
</field> |
|
||||
</record> |
|
||||
|
|
||||
</data></openerp> |
|
@ -1,29 +0,0 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
|
||||
<!-- |
|
||||
Copyright (C) 2015-Today GRAP (http://www.grap.coop) |
|
||||
@author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
--> |
|
||||
|
|
||||
<openerp><data> |
|
||||
|
|
||||
<record id="view_pos_switch_journal_wizard_form" model="ir.ui.view"> |
|
||||
<field name="model">pos.switch.journal.wizard</field> |
|
||||
<field name="arch" type="xml"> |
|
||||
<form> |
|
||||
<group col="4"> |
|
||||
<field name="order_id" /> |
|
||||
<field name="statement_line_id" /> |
|
||||
<field name="old_journal_id" /> |
|
||||
<field name="new_journal_id" widget="selection"/> |
|
||||
<field name="amount" /> |
|
||||
</group> |
|
||||
<footer> |
|
||||
<button name="button_switch_journal" string="Switch Journal" type="object" class="oe_highlight"/> |
|
||||
<button string="Cancel" class="oe_link" special="cancel" /> |
|
||||
</footer> |
|
||||
</form> |
|
||||
</field> |
|
||||
</record> |
|
||||
|
|
||||
</data></openerp> |
|
@ -0,0 +1,8 @@ |
|||||
|
============================== |
||||
|
Point Of Sale - Change Payment |
||||
|
============================== |
||||
|
|
||||
|
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
||||
|
!! This file is generated by oca-gen-addon-readme !! |
||||
|
!! changes will be overwritten. !! |
||||
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
@ -0,0 +1,2 @@ |
|||||
|
from . import models |
||||
|
from . import wizards |
@ -0,0 +1,20 @@ |
|||||
|
# Copyright (C) 2013 - Today: GRAP (http://www.grap.coop) |
||||
|
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
{ |
||||
|
"name": "Point Of Sale - Change Payment", |
||||
|
"version": "12.0.1.0.0", |
||||
|
"category": "Point Of Sale", |
||||
|
"author": "GRAP, Odoo Community Association (OCA)", |
||||
|
"website": "https://www.github.com/OCA/pos", |
||||
|
"license": "AGPL-3", |
||||
|
"depends": ["point_of_sale"], |
||||
|
"maintainers": ["legalsylvain"], |
||||
|
"development_status": "Beta", |
||||
|
"data": [ |
||||
|
"wizards/view_pos_payment_change_wizard.xml", |
||||
|
"views/view_pos_config.xml", |
||||
|
"views/view_pos_order.xml", |
||||
|
], |
||||
|
"installable": True, |
||||
|
} |
@ -0,0 +1,183 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * pos_payment_change |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 12.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2020-04-21 02:33+0000\n" |
||||
|
"PO-Revision-Date: 2020-04-21 02:33+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: pos_payment_change |
||||
|
#: model_terms:ir.ui.view,arch_db:pos_payment_change.view_pos_config_form |
||||
|
msgid "<span class=\"o_form_label\">Payment Change Policy</span>" |
||||
|
msgstr "<span class=\"o_form_label\">Méthode de changement de paiement</span>" |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: model:ir.model.fields,field_description:pos_payment_change.field_pos_payment_change_wizard_line__amount |
||||
|
msgid "Amount" |
||||
|
msgstr "Montant" |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: model_terms:ir.ui.view,arch_db:pos_payment_change.view_pos_payment_change_wizard_form |
||||
|
msgid "Cancel" |
||||
|
msgstr "Annuler" |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: model:ir.actions.act_window,name:pos_payment_change.action_pos_payment_change_wizard |
||||
|
#: model_terms:ir.ui.view,arch_db:pos_payment_change.view_pos_order_form |
||||
|
#: model_terms:ir.ui.view,arch_db:pos_payment_change.view_pos_payment_change_wizard_form |
||||
|
msgid "Change Payments" |
||||
|
msgstr "Changer les paiements" |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: model:ir.model.fields,field_description:pos_payment_change.field_pos_payment_change_wizard__create_uid |
||||
|
#: model:ir.model.fields,field_description:pos_payment_change.field_pos_payment_change_wizard_line__create_uid |
||||
|
msgid "Created by" |
||||
|
msgstr "Créé par" |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: model:ir.model.fields,field_description:pos_payment_change.field_pos_payment_change_wizard__create_date |
||||
|
#: model:ir.model.fields,field_description:pos_payment_change.field_pos_payment_change_wizard_line__create_date |
||||
|
msgid "Created on" |
||||
|
msgstr "Créé le" |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: code:addons/pos_payment_change/wizards/pos_payment_change_wizard.py:54 |
||||
|
#, python-format |
||||
|
msgid "Differences between the two values for the POS Order '%s':\n" |
||||
|
"\n" |
||||
|
" * Total of all the new payments %s;\n" |
||||
|
" * Total of the POS Order %s;\n" |
||||
|
"\n" |
||||
|
"Please change the payments." |
||||
|
msgstr "Différences entre les deux valeurs pour la vente '%s':\n" |
||||
|
"\n" |
||||
|
" * Total des nouveaux paiements %s;\n" |
||||
|
" * Total de la vente %s;\n" |
||||
|
"\n" |
||||
|
"Veuillez changer les paiements." |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: model:ir.model.fields,field_description:pos_payment_change.field_pos_payment_change_wizard__display_name |
||||
|
#: model:ir.model.fields,field_description:pos_payment_change.field_pos_payment_change_wizard_line__display_name |
||||
|
msgid "Display Name" |
||||
|
msgstr "Nom affiché" |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: model:ir.model.fields,field_description:pos_payment_change.field_pos_payment_change_wizard__id |
||||
|
#: model:ir.model.fields,field_description:pos_payment_change.field_pos_payment_change_wizard_line__id |
||||
|
msgid "ID" |
||||
|
msgstr "ID" |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: model:ir.model.fields,field_description:pos_payment_change.field_pos_payment_change_wizard_line__new_journal_id |
||||
|
msgid "Journal" |
||||
|
msgstr "Journal" |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: model:ir.model.fields,field_description:pos_payment_change.field_pos_payment_change_wizard____last_update |
||||
|
#: model:ir.model.fields,field_description:pos_payment_change.field_pos_payment_change_wizard_line____last_update |
||||
|
msgid "Last Modified on" |
||||
|
msgstr "Dernière modification le" |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: model:ir.model.fields,field_description:pos_payment_change.field_pos_payment_change_wizard__write_uid |
||||
|
#: model:ir.model.fields,field_description:pos_payment_change.field_pos_payment_change_wizard_line__write_uid |
||||
|
msgid "Last Updated by" |
||||
|
msgstr "Dernière mise à jour par" |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: model:ir.model.fields,field_description:pos_payment_change.field_pos_payment_change_wizard__write_date |
||||
|
#: model:ir.model.fields,field_description:pos_payment_change.field_pos_payment_change_wizard_line__write_date |
||||
|
msgid "Last Updated on" |
||||
|
msgstr "Dernière mise à jour le" |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: model:ir.model.fields,field_description:pos_payment_change.field_pos_payment_change_wizard__order_id |
||||
|
msgid "Order" |
||||
|
msgstr "Commande" |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: model:ir.model.fields,field_description:pos_payment_change.field_pos_config__payment_change_policy |
||||
|
msgid "Payment Change Policy" |
||||
|
msgstr "Méthode de changement de paiement" |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: model:ir.model.fields,help:pos_payment_change.field_pos_config__payment_change_policy |
||||
|
msgid "Payment Change Policy when users want to change the payment lines of a given PoS Order.\n" |
||||
|
"* 'Refund and Resale': Odoo will refund the current Pos Order to cancel it, and create a new PoS Order with the correct payment lines.\n" |
||||
|
"* 'Update Payments': Odoo will change payment lines.\n" |
||||
|
"\n" |
||||
|
"Note : In some countries the 'Update Payments' Option is not allowed by law, because orders history shouldn't not be altered." |
||||
|
msgstr "Méthode de changement de paiement quand les utilisateurs veulent changer des lignes de paiement d'une vente en caisse.\n" |
||||
|
"* 'Retourner et revendre': Odoo va réaliser un retour du la vente pour l'annuler, puis recréera une nouvelle vente, avec les paiements corrects.\n" |
||||
|
"* 'Modifier les paiements': Odoo va changer les lignes de paiements.\n" |
||||
|
"\n" |
||||
|
"Note : dans certains pays, l'option 'Modifier les paiements' n'est pas autorisé par la loi, parce que l'historique des ventes ne doit pas être altéré." |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: model:ir.model.fields,field_description:pos_payment_change.field_pos_payment_change_wizard__line_ids |
||||
|
#: model_terms:ir.ui.view,arch_db:pos_payment_change.view_pos_payment_change_wizard_form |
||||
|
msgid "Payment Lines" |
||||
|
msgstr "Lignes de paiement" |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: model:ir.model,name:pos_payment_change.model_pos_payment_change_wizard |
||||
|
msgid "PoS Payment Change Wizard" |
||||
|
msgstr "Assistant de changement de paiement du Point de Vente" |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: model:ir.model,name:pos_payment_change.model_pos_payment_change_wizard_line |
||||
|
msgid "PoS Payment Change Wizard Line" |
||||
|
msgstr "Ligne d'assistant de changement de paiement du Point de Vente" |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: model:ir.model,name:pos_payment_change.model_pos_config |
||||
|
msgid "Point of Sale Configuration" |
||||
|
msgstr "Paramétrage du point de vente" |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: model:ir.model,name:pos_payment_change.model_pos_order |
||||
|
msgid "Point of Sale Orders" |
||||
|
msgstr "Commandes du point de vente" |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: selection:pos.config,payment_change_policy:0 |
||||
|
msgid "Refund and Resale" |
||||
|
msgstr "Retourner et revendre" |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: model:ir.model.fields,field_description:pos_payment_change.field_pos_payment_change_wizard__amount_total |
||||
|
#: model_terms:ir.ui.view,arch_db:pos_payment_change.view_pos_payment_change_wizard_form |
||||
|
msgid "Total" |
||||
|
msgstr "Total" |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: code:addons/pos_payment_change/models/pos_config.py:43 |
||||
|
#, python-format |
||||
|
msgid "Unable to use the 'Update Payments' options for companies that have unalterable accounting." |
||||
|
msgstr "Impossible d'utiliser l'option 'Modifier les paiements' pour les sociétés qui ont une comptabilité inaltérable." |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: selection:pos.config,payment_change_policy:0 |
||||
|
msgid "Update Payments" |
||||
|
msgstr "Modifier les paiements" |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: model:ir.model.fields,field_description:pos_payment_change.field_pos_payment_change_wizard_line__wizard_id |
||||
|
msgid "Wizard" |
||||
|
msgstr "Assistant" |
||||
|
|
||||
|
#. module: pos_payment_change |
||||
|
#: code:addons/pos_payment_change/models/pos_order.py:80 |
||||
|
#, python-format |
||||
|
msgid "You can not change payments of the POS '%s' because the associated session '%s' has been closed!" |
||||
|
msgstr "Vous ne pouvez pas changer les paiements de la Vente '%s' car la session associée '%s' a été clôturé !" |
@ -0,0 +1,2 @@ |
|||||
|
from . import pos_config |
||||
|
from . import pos_order |
@ -0,0 +1,46 @@ |
|||||
|
# Copyright (C) 2020 - Today: GRAP (http://www.grap.coop) |
||||
|
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
from odoo import _, api, fields, models |
||||
|
from odoo.exceptions import ValidationError |
||||
|
|
||||
|
|
||||
|
class PosConfig(models.Model): |
||||
|
_inherit = "pos.config" |
||||
|
|
||||
|
_PAYMENT_CHANGE_POLICY_SELECTION = [ |
||||
|
('refund', "Refund and Resale"), |
||||
|
('update', "Update Payments"), |
||||
|
] |
||||
|
|
||||
|
payment_change_policy = fields.Selection( |
||||
|
selection=_PAYMENT_CHANGE_POLICY_SELECTION, |
||||
|
default="refund", required=True, |
||||
|
help="Payment Change Policy when users want" |
||||
|
" to change the payment lines of a given PoS Order.\n" |
||||
|
"* 'Refund and Resale': Odoo will refund the current" |
||||
|
" Pos Order to cancel it, and create a new PoS Order" |
||||
|
" with the correct payment lines.\n" |
||||
|
"* 'Update Payments': Odoo will change payment lines.\n\n" |
||||
|
"Note : In some countries the 'Update Payments' Option" |
||||
|
" is not allowed by law, because orders history shouldn't" |
||||
|
" not be altered.") |
||||
|
|
||||
|
@api.constrains("payment_change_policy") |
||||
|
def _check_payment_change_policy(self): |
||||
|
# Check if certification module is installed |
||||
|
# and if yes, if 'update payments' option is allowed |
||||
|
module_states = self.env["ir.module.module"].search([ |
||||
|
("name", "=", "l10n_fr_certification")] |
||||
|
).mapped("state") |
||||
|
if "installed" not in module_states: |
||||
|
return |
||||
|
for config in self.filtered( |
||||
|
lambda x: x.payment_change_policy == "update" |
||||
|
): |
||||
|
if config.company_id._is_accounting_unalterable(): |
||||
|
raise ValidationError(_( |
||||
|
"Unable to use the 'Update Payments' options" |
||||
|
" for companies that have unalterable accounting." |
||||
|
)) |
@ -0,0 +1,82 @@ |
|||||
|
# Copyright (C) 2015 - Today: GRAP (http://www.grap.coop) |
||||
|
# @author: Julien WESTE |
||||
|
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
from odoo import _, api, fields, models |
||||
|
from odoo.tools import float_is_zero |
||||
|
from odoo.exceptions import Warning as UserError |
||||
|
|
||||
|
|
||||
|
class PosOrder(models.Model): |
||||
|
_inherit = "pos.order" |
||||
|
|
||||
|
@api.multi |
||||
|
def change_payment(self, payment_lines): |
||||
|
""" |
||||
|
Change payment of a given order. |
||||
|
payment_lines should be a list of data that are |
||||
|
the argument of the Odoo Core function add_payment() |
||||
|
Return a list of order ids, depending on the |
||||
|
payment_change_policy of the related pos_config. |
||||
|
""" |
||||
|
self.ensure_one() |
||||
|
order_ids = [self.id] |
||||
|
|
||||
|
# Removing zero lines |
||||
|
precision = self.pricelist_id.currency_id.decimal_places |
||||
|
payment_lines = [ |
||||
|
x for x in payment_lines if not float_is_zero( |
||||
|
x["amount"], precision_digits=precision) |
||||
|
] |
||||
|
|
||||
|
self._check_payment_change_allowed() |
||||
|
|
||||
|
if self.config_id.payment_change_policy == "update": |
||||
|
self.statement_ids.with_context().unlink() |
||||
|
|
||||
|
# Create new payment |
||||
|
for line in payment_lines: |
||||
|
self.add_payment(line) |
||||
|
|
||||
|
elif self.config_id.payment_change_policy == "refund": |
||||
|
# Refund order and mark it as paid |
||||
|
# with same payment method as the original one |
||||
|
refund_result = self.refund() |
||||
|
refund_order = self.browse(refund_result["res_id"]) |
||||
|
|
||||
|
for statement in self.statement_ids: |
||||
|
refund_order.add_payment({ |
||||
|
"journal": statement.journal_id.id, |
||||
|
"amount": - statement.amount, |
||||
|
"payment_date": fields.Date.context_today(self), |
||||
|
}) |
||||
|
refund_order.action_pos_order_paid() |
||||
|
|
||||
|
# Resale order and mark it as paid |
||||
|
# with the new payment |
||||
|
resale_order = self.copy() |
||||
|
|
||||
|
for line in payment_lines: |
||||
|
resale_order.add_payment(line) |
||||
|
resale_order.action_pos_order_paid() |
||||
|
|
||||
|
order_ids += [refund_order.id, resale_order.id] |
||||
|
return order_ids |
||||
|
|
||||
|
@api.multi |
||||
|
def _check_payment_change_allowed(self): |
||||
|
"""Return True if the user can change the payment of a POS, depending |
||||
|
of the state of the current session.""" |
||||
|
closed_orders = self.filtered(lambda x: x.session_id.state == "closed") |
||||
|
if len(closed_orders): |
||||
|
raise UserError( |
||||
|
_( |
||||
|
"You can not change payments of the POS '%s' because" |
||||
|
" the associated session '%s' has been closed!" |
||||
|
% ( |
||||
|
", ".join(closed_orders.mapped("name")), |
||||
|
", ".join(closed_orders.mapped("session_id.name")), |
||||
|
) |
||||
|
) |
||||
|
) |
@ -0,0 +1,23 @@ |
|||||
|
* Go to Point of Sale > Configuration > Point of Sale |
||||
|
* Edit your point of sale, and select a value for the field |
||||
|
'Payment Change Policy'. |
||||
|
|
||||
|
Two options are available: |
||||
|
|
||||
|
* 'Refund and Resale': Odoo will refund the current |
||||
|
Pos Order to cancel it, and create a new PoS Order |
||||
|
with the correct payment lines |
||||
|
|
||||
|
* 'Update Payments': Odoo will change payment lines. |
||||
|
|
||||
|
.. figure:: ../static/description/pos_config_form.png |
||||
|
|
||||
|
|
||||
|
**Note** |
||||
|
In some countries the 'Update Payments' Option |
||||
|
is not allowed by law, because orders history shouldn't not be altered. |
||||
|
|
||||
|
For that purpose, a constrains is present to check the value of this |
||||
|
field. If the module ``l10n_fr_certification`` is installed and if the |
||||
|
current company has an inalterable accounting, it will not be possible |
||||
|
to select the value 'Update Payments'. |
@ -0,0 +1,4 @@ |
|||||
|
The development of this module has been financially supported by: |
||||
|
|
||||
|
* GRAP, Groupement Régional Alimentaire de proximité (www.grap.coop) |
||||
|
* Vracoop (www.vracoop.fr) |
@ -0,0 +1,6 @@ |
|||||
|
This module extends the functionnality of the Odoo Point of Sale to |
||||
|
allow the cashier to change the payments of a PoS order. |
||||
|
|
||||
|
This feature is usefull when the user realized that he did a mistake, |
||||
|
just after he marked the order as paid, or during the close of the session, |
||||
|
Only if entries has not been generated. |
@ -0,0 +1,19 @@ |
|||||
|
* Go to a PoS Order |
||||
|
|
||||
|
* Click on the button 'Change Payments' |
||||
|
|
||||
|
.. figure:: ../static/description/pos_order_form.png |
||||
|
|
||||
|
* In the pop up wizard, select the real payment(s) that have been |
||||
|
used to pay the order |
||||
|
|
||||
|
.. figure:: ../static/description/pos_payment_change_wizard_form.png |
||||
|
|
||||
|
* Then click on the button 'Change Payments' |
||||
|
|
||||
|
**Note** |
||||
|
|
||||
|
If the option 'Refund and Resale' is selected, changing the payments will |
||||
|
display the three PoS orders. the oringal one, the refund one, and the new one. |
||||
|
|
||||
|
.. figure:: ../static/description/pos_order_tree.png |
After Width: 951 | Height: 357 | Size: 34 KiB |
After Width: 473 | Height: 204 | Size: 14 KiB |
After Width: 957 | Height: 193 | Size: 32 KiB |
After Width: 971 | Height: 375 | Size: 24 KiB |
@ -1,2 +1 @@ |
|||||
# coding: utf-8 |
|
||||
from . import test_module |
from . import test_module |
@ -0,0 +1,172 @@ |
|||||
|
# Copyright (C) 2018 - Today: GRAP (http://www.grap.coop) |
||||
|
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
from odoo import fields |
||||
|
from odoo.tests.common import TransactionCase |
||||
|
from odoo.exceptions import UserError |
||||
|
|
||||
|
|
||||
|
class TestModule(TransactionCase): |
||||
|
"""Tests for 'Point of Sale - Change Payment' Module""" |
||||
|
|
||||
|
def setUp(self): |
||||
|
super().setUp() |
||||
|
self.PosSession = self.env["pos.session"] |
||||
|
self.PosOrder = self.env["pos.order"] |
||||
|
self.AccountJournal = self.env["account.journal"] |
||||
|
self.PosMakePayment = self.env['pos.make.payment'] |
||||
|
self.PosPaymentChangeWizard = self.env["pos.payment.change.wizard"] |
||||
|
self.PosPaymentChangeWizardLine = self.env[ |
||||
|
"pos.payment.change.wizard.line" |
||||
|
] |
||||
|
self.product = self.env.ref("product.product_product_3") |
||||
|
self.pos_config = self.env.ref("point_of_sale.pos_config_main").copy() |
||||
|
|
||||
|
def _initialize_journals_open_session(self): |
||||
|
|
||||
|
self.check_journal = self.AccountJournal.create({ |
||||
|
"name": "Demo Check Journal", |
||||
|
"type": "bank", |
||||
|
"journal_user": True, |
||||
|
}) |
||||
|
self.cash_journal = self.AccountJournal.create({ |
||||
|
"name": "Demo Cash Journal", |
||||
|
"type": "cash", |
||||
|
"journal_user": True, |
||||
|
}) |
||||
|
|
||||
|
# create new session and open it |
||||
|
self.pos_config.journal_ids = [ |
||||
|
self.check_journal.id, |
||||
|
self.cash_journal.id, |
||||
|
] |
||||
|
self.pos_config.open_session_cb() |
||||
|
self.session = self.pos_config.current_session_id |
||||
|
self.check_statement = self.session.statement_ids.filtered( |
||||
|
lambda x: x.journal_id == self.check_journal |
||||
|
) |
||||
|
self.cash_statement = self.session.statement_ids.filtered( |
||||
|
lambda x: x.journal_id == self.cash_journal |
||||
|
) |
||||
|
|
||||
|
def _sale(self, journal_1, price_1, journal_2=False, price_2=0.0): |
||||
|
price = price_1 + price_2 |
||||
|
line_vals = { |
||||
|
"name": "OL/0001", |
||||
|
"product_id": self.product.id, |
||||
|
"qty": 1.0, |
||||
|
"price_unit": price, |
||||
|
"price_subtotal": price, |
||||
|
"price_subtotal_incl": price, |
||||
|
} |
||||
|
order = self.PosOrder.create({ |
||||
|
"session_id": self.session.id, |
||||
|
"amount_tax": 0, |
||||
|
"amount_total": price, |
||||
|
"amount_paid": price, |
||||
|
"amount_return": 0, |
||||
|
"lines": [[0, False, line_vals]], |
||||
|
}) |
||||
|
order.add_payment({ |
||||
|
'amount': price_1, |
||||
|
'payment_date': fields.Date.today(), |
||||
|
'payment_name': "Demo", |
||||
|
'journal': journal_1.id, |
||||
|
}) |
||||
|
if journal_2: |
||||
|
order.add_payment({ |
||||
|
'amount': price_2, |
||||
|
'payment_date': fields.Date.today(), |
||||
|
'payment_name': "Demo", |
||||
|
'journal': journal_2.id, |
||||
|
}) |
||||
|
order.action_pos_order_paid() |
||||
|
return order |
||||
|
|
||||
|
def _change_payment( |
||||
|
self, order, journal_1, amount_1, journal_2=False, amount_2=0.0 |
||||
|
): |
||||
|
# Switch to check journal |
||||
|
wizard = self.PosPaymentChangeWizard.with_context( |
||||
|
active_id=order.id |
||||
|
).create({}) |
||||
|
self.PosPaymentChangeWizardLine.with_context( |
||||
|
active_id=order.id |
||||
|
).create( |
||||
|
{ |
||||
|
"wizard_id": wizard.id, |
||||
|
"new_journal_id": journal_1.id, |
||||
|
"amount": amount_1, |
||||
|
} |
||||
|
) |
||||
|
if journal_2: |
||||
|
self.PosPaymentChangeWizardLine.with_context( |
||||
|
active_id=order.id |
||||
|
).create( |
||||
|
{ |
||||
|
"wizard_id": wizard.id, |
||||
|
"new_journal_id": journal_2.id, |
||||
|
"amount": amount_2, |
||||
|
} |
||||
|
) |
||||
|
wizard.button_change_payment() |
||||
|
|
||||
|
# Test Section |
||||
|
def test_01_payment_change_policy_update(self): |
||||
|
self.pos_config.payment_change_policy = "update" |
||||
|
|
||||
|
self._initialize_journals_open_session() |
||||
|
# Make a sale with 35 in cash journal and 65 in check |
||||
|
order = self._sale(self.cash_journal, 35, self.check_journal, 65) |
||||
|
|
||||
|
order_qty = len(self.PosOrder.search([])) |
||||
|
|
||||
|
with self.assertRaises(UserError): |
||||
|
# Should not work if total is not correct |
||||
|
self._change_payment( |
||||
|
order, self.cash_journal, 10, self.check_journal, 10) |
||||
|
|
||||
|
self._change_payment( |
||||
|
order, self.cash_journal, 10, self.check_journal, 90) |
||||
|
|
||||
|
# check Session |
||||
|
self.assertEqual( |
||||
|
self.cash_statement.balance_end, |
||||
|
10, |
||||
|
"Bad recompute of the balance for the statement cash", |
||||
|
) |
||||
|
|
||||
|
self.assertEqual( |
||||
|
self.check_statement.balance_end, |
||||
|
90, |
||||
|
"Bad recompute of the balance for the statement check", |
||||
|
) |
||||
|
|
||||
|
# Check Order quantity |
||||
|
self.assertEqual( |
||||
|
order_qty, |
||||
|
len(self.PosOrder.search([])), |
||||
|
"In 'Update' mode, changing payment should not create" |
||||
|
" other PoS Orders", |
||||
|
) |
||||
|
|
||||
|
def test_02_payment_change_policy_refund(self): |
||||
|
self.pos_config.payment_change_policy = "refund" |
||||
|
|
||||
|
self._initialize_journals_open_session() |
||||
|
# Make a sale with 35 in cash journal and 65 in check |
||||
|
order = self._sale(self.cash_journal, 35, self.check_journal, 65) |
||||
|
|
||||
|
order_qty = len(self.PosOrder.search([])) |
||||
|
|
||||
|
self._change_payment( |
||||
|
order, self.cash_journal, 50, self.check_journal, 50) |
||||
|
|
||||
|
# Check Order quantity |
||||
|
self.assertEqual( |
||||
|
order_qty + 2, |
||||
|
len(self.PosOrder.search([])), |
||||
|
"In 'Refund' mode, changing payment should generate" |
||||
|
" two new PoS Orders", |
||||
|
) |
@ -0,0 +1,29 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<!-- |
||||
|
Copyright (C) 2020-Today GRAP (http://www.grap.coop) |
||||
|
@author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
||||
|
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
--> |
||||
|
|
||||
|
<odoo> |
||||
|
|
||||
|
<record id="view_pos_config_form" model="ir.ui.view"> |
||||
|
<field name="model">pos.config</field> |
||||
|
<field name="inherit_id" ref="point_of_sale.pos_config_view_form"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<xpath expr="//div[hasclass('o_settings_container')][2]" |
||||
|
position="inside"> |
||||
|
<div class="col-12 col-lg-6 o_setting_box"> |
||||
|
<div class="o_setting_right_pane"> |
||||
|
<span class="o_form_label">Payment Change Policy</span> |
||||
|
<div class="content-group mt16"> |
||||
|
<field name="payment_change_policy" colspan="4" |
||||
|
nolabel="1"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</xpath> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
</odoo> |
@ -0,0 +1,2 @@ |
|||||
|
from . import pos_payment_change_wizard |
||||
|
from . import pos_payment_change_wizard_line |
@ -0,0 +1,77 @@ |
|||||
|
# Copyright (C) 2015-Today GRAP (http://www.grap.coop) |
||||
|
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
from odoo import _, api, fields, models |
||||
|
from odoo.exceptions import Warning as UserError |
||||
|
|
||||
|
|
||||
|
class PosPaymentChangeWizard(models.TransientModel): |
||||
|
_name = "pos.payment.change.wizard" |
||||
|
_description = "PoS Payment Change Wizard" |
||||
|
|
||||
|
# Column Section |
||||
|
order_id = fields.Many2one( |
||||
|
comodel_name="pos.order", string="Order", readonly=True |
||||
|
) |
||||
|
|
||||
|
line_ids = fields.One2many( |
||||
|
comodel_name="pos.payment.change.wizard.line", |
||||
|
inverse_name="wizard_id", |
||||
|
string="Payment Lines", |
||||
|
) |
||||
|
|
||||
|
amount_total = fields.Float(string="Total", readonly=True) |
||||
|
|
||||
|
# View Section |
||||
|
@api.model |
||||
|
def default_get(self, fields): |
||||
|
PosOrder = self.env["pos.order"] |
||||
|
res = super().default_get(fields) |
||||
|
order = PosOrder.browse(self._context.get("active_id")) |
||||
|
res.update({"order_id": order.id}) |
||||
|
res.update({"amount_total": order.amount_total}) |
||||
|
return res |
||||
|
|
||||
|
# View section |
||||
|
@api.multi |
||||
|
def button_change_payment(self): |
||||
|
self.ensure_one() |
||||
|
order = self.order_id |
||||
|
|
||||
|
# Check if the total is correct |
||||
|
total = 0 |
||||
|
for line in self.line_ids: |
||||
|
total += line.amount |
||||
|
if total != self.amount_total: |
||||
|
raise UserError( |
||||
|
_( |
||||
|
"Differences between the two values for the POS" |
||||
|
" Order '%s':\n\n" |
||||
|
" * Total of all the new payments %s;\n" |
||||
|
" * Total of the POS Order %s;\n\n" |
||||
|
"Please change the payments." |
||||
|
% (order.name, total, order.amount_total) |
||||
|
) |
||||
|
) |
||||
|
|
||||
|
# Change payment |
||||
|
new_payments = [{ |
||||
|
"journal": line.new_journal_id.id, |
||||
|
"amount": line.amount, |
||||
|
"payment_date": fields.Date.context_today(self), |
||||
|
} for line in self.line_ids] |
||||
|
|
||||
|
order_ids = order.change_payment(new_payments) |
||||
|
|
||||
|
if len(order_ids) == 1: |
||||
|
# if policy is 'update', only close the pop up |
||||
|
action = {'type': 'ir.actions.act_window_close'} |
||||
|
else: |
||||
|
# otherwise (refund policy), displays the 3 orders |
||||
|
action = self.env.ref( |
||||
|
"point_of_sale.action_pos_pos_form" |
||||
|
).read()[0] |
||||
|
action['domain'] = [('id', 'in', order_ids)] |
||||
|
|
||||
|
return action |
@ -0,0 +1,46 @@ |
|||||
|
# Copyright (C) 2015 - Today: GRAP (http://www.grap.coop) |
||||
|
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
from odoo import api, fields, models |
||||
|
|
||||
|
|
||||
|
class PosPaymentChangeWizardLine(models.TransientModel): |
||||
|
_name = "pos.payment.change.wizard.line" |
||||
|
_description = "PoS Payment Change Wizard Line" |
||||
|
|
||||
|
wizard_id = fields.Many2one( |
||||
|
comodel_name="pos.payment.change.wizard", required=True, |
||||
|
) |
||||
|
|
||||
|
new_journal_id = fields.Many2one( |
||||
|
comodel_name="account.journal", |
||||
|
string="Journal", |
||||
|
required=True, |
||||
|
domain=lambda s: s._domain_new_journal_id(), |
||||
|
) |
||||
|
|
||||
|
amount = fields.Float(string="Amount", required=True) |
||||
|
|
||||
|
@api.model |
||||
|
def _domain_new_journal_id(self): |
||||
|
PosOrder = self.env["pos.order"] |
||||
|
order = PosOrder.browse(self.env.context.get("active_id")) |
||||
|
# return [("id", "in", order.session_id.journal_ids.ids)] |
||||
|
return [("id", "in", order.mapped( |
||||
|
"session_id.statement_ids.journal_id").ids)] |
||||
|
|
||||
|
# View Section |
||||
|
@api.model |
||||
|
def default_get(self, fields): |
||||
|
res = super().default_get(fields) |
||||
|
if "line_ids" not in self._context: |
||||
|
return res |
||||
|
balance = self._context.get("amount_total", 0.0) |
||||
|
for line in self.wizard_id.resolve_2many_commands( |
||||
|
"line_ids", |
||||
|
self._context["line_ids"], |
||||
|
fields=["amount"]): |
||||
|
balance -= line.get("amount") |
||||
|
res.update({'amount': balance}) |
||||
|
return res |
@ -0,0 +1,43 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<!-- |
||||
|
Copyright (C) 2015-Today GRAP (http://www.grap.coop) |
||||
|
@author: Sylvain LE GAL (https://twitter.com/legalsylvain) |
||||
|
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
--> |
||||
|
|
||||
|
<odoo> |
||||
|
|
||||
|
<record id="view_pos_payment_change_wizard_form" model="ir.ui.view"> |
||||
|
<field name="model">pos.payment.change.wizard</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form> |
||||
|
<group col="4"> |
||||
|
<field name="order_id" /> |
||||
|
<field name="amount_total" /> |
||||
|
<newline /> |
||||
|
<field name="line_ids" colspan="4" |
||||
|
context="{'line_ids': line_ids, 'amount_total': amount_total}"> |
||||
|
<tree string="Payment Lines" editable="bottom"> |
||||
|
<field name="new_journal_id" options="{'no_open': True, 'no_create_edit': True}"/> |
||||
|
<field name="amount" sum="Total"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</group> |
||||
|
<footer> |
||||
|
<button name="button_change_payment" string="Change Payments" |
||||
|
type="object" class="oe_highlight"/> |
||||
|
<button string="Cancel" class="oe_link" special="cancel" /> |
||||
|
</footer> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="action_pos_payment_change_wizard" model="ir.actions.act_window"> |
||||
|
<field name="name">Change Payments</field> |
||||
|
<field name="res_model">pos.payment.change.wizard</field> |
||||
|
<field name="view_type">form</field> |
||||
|
<field name="view_mode">form</field> |
||||
|
<field name="target">new</field> |
||||
|
</record> |
||||
|
|
||||
|
</odoo> |