Browse Source

Merge 0575538523 into 45a15ac568

pull/449/merge
Jordi Ballester Alomar 4 years ago
committed by GitHub
parent
commit
3a52eb2b7d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      pos_statement_closing_balance/__init__.py
  2. 22
      pos_statement_closing_balance/__manifest__.py
  3. 2
      pos_statement_closing_balance/models/__init__.py
  4. 14
      pos_statement_closing_balance/models/account_journal.py
  5. 34
      pos_statement_closing_balance/models/pos_session.py
  6. 4
      pos_statement_closing_balance/readme/CONFIGURATION.rst
  7. 3
      pos_statement_closing_balance/readme/CONTRIBUTORS.rst
  8. 8
      pos_statement_closing_balance/readme/DESCRIPTION.rst
  9. 7
      pos_statement_closing_balance/readme/USAGE.rst
  10. 1
      pos_statement_closing_balance/tests/__init__.py
  11. 84
      pos_statement_closing_balance/tests/test_pos_statement_closing_balance.py
  12. 14
      pos_statement_closing_balance/views/account_journal_views.xml
  13. 19
      pos_statement_closing_balance/views/pos_session_views.xml
  14. 1
      pos_statement_closing_balance/wizards/__init__.py
  15. 128
      pos_statement_closing_balance/wizards/pos_update_statement_closing_balance.py
  16. 34
      pos_statement_closing_balance/wizards/pos_update_statement_closing_balance.xml

2
pos_statement_closing_balance/__init__.py

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

22
pos_statement_closing_balance/__manifest__.py

@ -0,0 +1,22 @@
# Copyright 2020 ForgeFlow, S.L.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{
'name': 'POS Statement Closing Balance',
'version': '12.0.1.0.1',
'category': 'Point Of Sale',
'summary': 'Allows to set a closing balance in your statements and '
'auto-post the difference between theoretical and actual.',
'author': 'ForgeFlow, Odoo Community Association (OCA)',
'website': 'http://www.github.com/OCA/pos',
'license': 'AGPL-3',
'depends': [
'pos_cash_move_reason',
],
'data': [
'wizards/pos_update_statement_closing_balance.xml',
'views/pos_session_views.xml',
'views/account_journal_views.xml',
],
'installable': True,
}

2
pos_statement_closing_balance/models/__init__.py

@ -0,0 +1,2 @@
from . import pos_session
from . import account_journal

14
pos_statement_closing_balance/models/account_journal.py

@ -0,0 +1,14 @@
# Copyright 2020 ForgeFlow, S.L.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import fields, models
class AccountJournal(models.Model):
_inherit = 'account.journal'
pos_control_ending_balance = fields.Boolean(
'Control ending balance in POS')
pos_move_reason_id = fields.Many2one(
string='Default reason POS adjustments',
comodel_name='pos.move.reason',
)

34
pos_statement_closing_balance/models/pos_session.py

@ -0,0 +1,34 @@
# Copyright 2020 ForgeFlow, S.L.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import api, models, _
from odoo.exceptions import ValidationError
class PosSession(models.Model):
_inherit = "pos.session"
@api.multi
def button_update_statement_ending_balance(self):
self.ensure_one()
action = self.env.ref(
"pos_statement_closing_balance."
"action_pos_update_bank_statement_closing_balance")
result = action.read()[0]
return result
@api.multi
def _check_pos_session_bank_balance(self):
for session in self:
for statement in session.statement_ids:
if statement.journal_id.pos_control_ending_balance and \
(statement != session.cash_register_id) and (
statement.balance_end != statement.balance_end_real):
raise ValidationError(_(
'Mismatch in the closing balance '
'for a non-cash statement.'))
return True
@api.multi
def action_pos_session_closing_control(self):
self._check_pos_session_bank_balance()
return super(PosSession, self).action_pos_session_closing_control()

4
pos_statement_closing_balance/readme/CONFIGURATION.rst

@ -0,0 +1,4 @@
* Go to *Invoicing > Configuration > Journals* and set, for each Journal
that will be used in the POS, the flag 'Control ending balance in POS' if
you expect users to enter the ending balance, and enter the default POS
move reason to be used in the adjustment.

3
pos_statement_closing_balance/readme/CONTRIBUTORS.rst

@ -0,0 +1,3 @@
* ForgeFlow
* Jordi Ballester Alomar <jordi.ballester@forgeflow.com>

8
pos_statement_closing_balance/readme/DESCRIPTION.rst

@ -0,0 +1,8 @@
This module extends the functionality of point of sale to allow users to input
the ending balances of the payment methods when they close a POS Session.
The system will then post the difference to the 'Liquidity Transfers' account.
Currently it's only possible to define the ending balance for the cash
if you configure "Cash Control" in the POS Configuration. But that setting
will not allow users to enter the ending balances for credit card transactions
, for example.

7
pos_statement_closing_balance/readme/USAGE.rst

@ -0,0 +1,7 @@
* Go to *Point of Sale*, then to a session and go to *Settings*.
* Define the payment methods that you want to use.
* Start the Session and create some POS orders.
* Go back to the POS Session and press "Close".
* Press the button "Update Ending Balances" in the POS Session, and enter
the final balance in the column "Balance End Real".

1
pos_statement_closing_balance/tests/__init__.py

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

84
pos_statement_closing_balance/tests/test_pos_statement_closing_balance.py

@ -0,0 +1,84 @@
# Copyright 2020 ForgeFlow, S.L.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo.tests.common import TransactionCase
from odoo.exceptions import ValidationError
class TestPosStatementClosingBalance(TransactionCase):
def setUp(self):
super(TestPosStatementClosingBalance, self).setUp()
self.pos_config = self.env["pos.config"].create({"name": "PoS config"})
self.wizard_reason = self.env['wizard.pos.move.reason']
account = self.env['account.account'].create({
'code': '9999',
'name': 'Test',
'user_type_id': self.env.ref(
"account.data_account_type_liquidity").id
})
self.bank_journal = self.env["account.journal"].create({
"name": "Test bank",
"code": "TB1",
"type": "bank",
"pos_control_ending_balance": True,
})
self.pos_move_reason = self.env['pos.move.reason'].create({
'name': 'Bank closing reason',
'is_income_reason': True,
'is_expense_reason': True,
'expense_account_id': account.id,
'income_account_id': account.id,
'journal_ids': self.bank_journal.ids,
'company_id': self.env.ref('base.main_company').id,
})
self.bank_journal.pos_move_reason_id = self.pos_move_reason
self.pos_config.journal_ids += self.bank_journal
self.pos_config.open_session_cb()
self.session = self.pos_config.current_session_id
self.session.action_pos_session_open()
def test_wizard(self):
journal = self.session.journal_ids.filtered(lambda j: j.code == 'TB1')
wizard = self.wizard_reason.with_context(
active_id=self.session.id,
default_move_type='income').create({
'move_reason_id': self.pos_move_reason.id,
'journal_id': self.bank_journal.id,
'statement_id': self.session.statement_ids.filtered(
lambda s: s.journal_id == self.bank_journal).id,
'amount': 10,
'name': 'Test Bank Deposit',
})
wizard.apply()
self.assertEqual(
self.session.statement_ids.filtered(
lambda r: r.journal_id.id == journal.id
).difference,
-10.0,
)
with self.assertRaises(ValidationError):
self.session.action_pos_session_closing_control()
wizard = (
self.env["pos.update.bank.statement.closing.balance"]
.with_context(
active_model="pos.session", active_ids=self.session.ids
)
.create({})
)
for item in wizard.item_ids:
item.balance_end_real = 2.0
wizard.action_confirm()
self.assertEqual(
self.session.statement_ids.filtered(
lambda r: r.journal_id.id == journal.id
).balance_end,
2.0,
)
self.assertEqual(
self.session.statement_ids.filtered(
lambda r: r.journal_id.id == journal.id
).difference,
0,
)
self.session.action_pos_session_closing_control()
self.assertEqual(self.session.state, 'closed')

14
pos_statement_closing_balance/views/account_journal_views.xml

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_account_journal_form" model="ir.ui.view">
<field name="name">account.journal.form</field>
<field name="model">account.journal</field>
<field name="inherit_id" ref="account.view_account_journal_form"/>
<field name="arch" type="xml">
<field name="type" position="after">
<field name="pos_control_ending_balance" attrs="{'invisible':[('journal_user', '=', False)]}"/>
<field name="pos_move_reason_id" attrs="{'invisible':[('pos_control_ending_balance', '=', False)]}"/>
</field>
</field>
</record>
</odoo>

19
pos_statement_closing_balance/views/pos_session_views.xml

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="view_pos_session_form" model="ir.ui.view">
<field name="name">pos.session.form.view</field>
<field name="model">pos.session</field>
<field name="inherit_id" ref="point_of_sale.view_pos_session_form"/>
<field name="arch" type="xml">
<button name="open_cashbox" position="after">
<button name="button_update_statement_ending_balance"
class="oe_stat_button"
attrs="{'invisible':[('state', '=', 'closed')]}"
icon="fa-money"
type="object" context="{'balance': 'end'}">
<span class="o_stat_text">Update Ending Balances</span>
</button>
</button>
</field>
</record>
</odoo>

1
pos_statement_closing_balance/wizards/__init__.py

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

128
pos_statement_closing_balance/wizards/pos_update_statement_closing_balance.py

@ -0,0 +1,128 @@
# Copyright 2020 ForgeFlow, S.L.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import api, fields, models, _
from odoo.exceptions import UserError
class POSBankStatementUpdateClosingBalance(models.TransientModel):
_name = "pos.update.bank.statement.closing.balance"
_description = 'POS Update Bank Statement Closing Balance'
session_id = fields.Many2one(
comodel_name='pos.session',
)
item_ids = fields.One2many(
comodel_name="pos.update.bank.statement.closing.balance.line",
inverse_name="wiz_id",
string="Items",
)
@api.model
def _prepare_item(self, session, statement):
return {
"statement_id": statement.id,
"name": statement.name,
"journal_id": statement.journal_id.id,
"balance_start": statement.balance_start,
"total_entry_encoding": statement.total_entry_encoding,
"currency_id": statement.currency_id.id,
"pos_move_reason_id": statement.journal_id.pos_move_reason_id.id,
}
@api.model
def default_get(self, flds):
res = super().default_get(flds)
session_obj = self.env["pos.session"]
active_ids = self.env.context["active_ids"] or []
active_model = self.env.context["active_model"]
if not active_ids:
return res
assert active_model == "pos.session", \
"Bad context propagation"
items = []
if len(active_ids) > 1:
raise UserError(_('You cannot start the closing '
'balance for multiple POS sessions'))
session = session_obj.browse(active_ids[0])
for statement in session.statement_ids.filtered(
lambda s: s.journal_id.pos_control_ending_balance):
items.append([0, 0, self._prepare_item(session, statement)])
res["session_id"] = session.id
res["item_ids"] = items
return res
@api.model
def _prepare_wizard_pos_move_reason(self, item):
return {
'move_reason_id':
item.statement_id.journal_id.pos_move_reason_id.id,
'amount': abs(item.difference),
'journal_id': item.journal_id.id,
'name': _("Ending balance adjustment")
}
@api.multi
def action_confirm(self):
self.ensure_one()
for item in self.item_ids:
if item.difference:
if item.difference > 0.0:
default_move_type = "income"
else:
default_move_type = "expense"
wizard = (
self.env["wizard.pos.move.reason"]
.with_context(
active_model="pos.session",
active_ids=self.session_id.ids,
active_id=self.session_id.id,
default_move_type=default_move_type,
).create(self._prepare_wizard_pos_move_reason(item))
)
wizard.apply()
item.statement_id.balance_end_real = item.balance_end_real
return True
class BankStatementLineUpdateEndingBalanceLine(models.TransientModel):
_name = "pos.update.bank.statement.closing.balance.line"
_description = 'POS Update Bank Statement Closing Balance Line'
wiz_id = fields.Many2one(
comodel_name='pos.update.bank.statement.closing.balance',
required=True,
)
statement_id = fields.Many2one(
comodel_name='account.bank.statement',
)
name = fields.Char(
related='statement_id.name'
)
journal_id = fields.Many2one(
comodel_name='account.journal',
related='statement_id.journal_id',
)
balance_start = fields.Monetary(
related='statement_id.balance_start',
)
total_entry_encoding = fields.Monetary(
related='statement_id.total_entry_encoding',
)
balance_end = fields.Monetary(compute='_compute_balance_end')
balance_end_real = fields.Monetary(default=0.0)
difference = fields.Monetary(compute='_compute_balance_end')
currency_id = fields.Many2one(
comodel_name='res.currency',
related='statement_id.currency_id'
)
pos_move_reason_id = fields.Many2one(
comodel_name='pos.move.reason',
string='Reason',
)
def _compute_balance_end(self):
for rec in self:
rec.balance_end = rec.balance_start + rec.total_entry_encoding
rec.difference = rec.balance_end_real - rec.balance_end

34
pos_statement_closing_balance/wizards/pos_update_statement_closing_balance.xml

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="pos_update_bank_statement_closing_balance_form" model="ir.ui.view">
<field name="name">pos.update.bank.statement.closing.balance.form</field>
<field name="model">pos.update.bank.statement.closing.balance</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Update Ending Balance">
<field name="item_ids" nolabel="1">
<tree string="Statements" create="0" editable="top">
<field name="name"/>
<field name="journal_id"/>
<field name="balance_start"/>
<field name="total_entry_encoding"/>
<field name="balance_end_real"/>
<field name="currency_id" groups="base.group_multi_currency"/>
<field name="pos_move_reason_id" invisible="1"/>
</tree>
</field>
<footer>
<button name="action_confirm" string="Confirm" type="object" class="btn-primary"/>
<button special="cancel" string="Cancel" class="btn-default"/>
</footer>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_pos_update_bank_statement_closing_balance">
<field name="name">Update Ending Balances</field>
<field name="res_model">pos.update.bank.statement.closing.balance</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</odoo>
Loading…
Cancel
Save