Adrien Peiffer (ACSONE)
9 years ago
committed by
Sylvain LE GAL
12 changed files with 402 additions and 0 deletions
-
62pos_cash_move_reason/README.rst
-
5pos_cash_move_reason/__init__.py
-
19pos_cash_move_reason/__openerp__.py
-
45pos_cash_move_reason/i18n/fr.po
-
43pos_cash_move_reason/i18n/pos_cash_move_reason.pot
-
BINpos_cash_move_reason/static/description/icon.png
-
BINpos_cash_move_reason/static/description/pos_cash_move_reason_02.png
-
5pos_cash_move_reason/tests/__init__.py
-
106pos_cash_move_reason/tests/test_pos_cash_move_reason.py
-
5pos_cash_move_reason/wizard/__init__.py
-
86pos_cash_move_reason/wizard/pos_box.py
-
26pos_cash_move_reason/wizard/pos_box.xml
@ -0,0 +1,62 @@ |
|||
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg |
|||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html |
|||
:alt: License: AGPL-3 |
|||
|
|||
====================== |
|||
POS cash in-out reason |
|||
====================== |
|||
|
|||
This module allow to define some products as reason for the functionality of |
|||
"Put Money In" and "Take Money Out" available in point of sale session. |
|||
So, with this module it's possible to impact directly an expense or income |
|||
account which is defined on the related product or in its category. |
|||
|
|||
Configuration |
|||
============= |
|||
|
|||
You need to configure some products that can be used on "Put Money In" and |
|||
"Take Money Out". You have to set Point of Sale Cash In or Out and income and |
|||
expense account. |
|||
|
|||
Usage |
|||
===== |
|||
|
|||
You can use configured products on "Put Money In" and "Take Money Out" wizard available in point of sale session: |
|||
|
|||
.. figure:: static/description/pos_cash_move_reason_02.png |
|||
:alt: Take money out wizard |
|||
|
|||
|
|||
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas |
|||
:alt: Try me on Runbot |
|||
:target: https://runbot.odoo-community.org/runbot/184/8.0 |
|||
|
|||
|
|||
Bug Tracker |
|||
=========== |
|||
|
|||
Bugs are tracked on `GitHub Issues <https://github.com/OCA/pos/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 |
|||
`here <https://github.com/OCA/pos/issues/new?body=module:%20pos_cash_move_reason%0Aversion:%208.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. |
|||
|
|||
Credits |
|||
======= |
|||
|
|||
Contributors |
|||
------------ |
|||
|
|||
* Adrien Peiffer <adrien.peiffer@acsone.eu> |
|||
|
|||
Maintainer |
|||
---------- |
|||
|
|||
.. image:: https://odoo-community.org/logo.png |
|||
:alt: Odoo Community Association |
|||
:target: https://odoo-community.org |
|||
|
|||
This module is maintained by the OCA. |
|||
|
|||
OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. |
|||
|
|||
To contribute to this module, please visit https://odoo-community.org. |
@ -0,0 +1,5 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright 2016 ACSONE SA/NV (<http://acsone.eu>) |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
from . import wizard |
@ -0,0 +1,19 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright 2016 ACSONE SA/NV (<http://acsone.eu>) |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
{ |
|||
'name': "POS cash in-out reason", |
|||
'summary': """""", |
|||
'author': 'ACSONE SA/NV,' |
|||
'Odoo Community Association (OCA)', |
|||
'website': "http://acsone.eu", |
|||
'category': 'POS', |
|||
'version': '8.0.1.0.0', |
|||
'license': 'AGPL-3', |
|||
'depends': [ |
|||
'point_of_sale', |
|||
], |
|||
'data': [ |
|||
'wizard/pos_box.xml', |
|||
], |
|||
} |
@ -0,0 +1,45 @@ |
|||
# Translation of Odoo Server. |
|||
# This file contains the translation of the following modules: |
|||
# * pos_cash_move_reason |
|||
# |
|||
msgid "" |
|||
msgstr "" |
|||
"Project-Id-Version: Odoo Server 8.0\n" |
|||
"Report-Msgid-Bugs-To: \n" |
|||
"POT-Creation-Date: 2016-04-12 11:10+0000\n" |
|||
"PO-Revision-Date: 2016-04-12 11:10+0000\n" |
|||
"Last-Translator: <>\n" |
|||
"Language-Team: \n" |
|||
"MIME-Version: 1.0\n" |
|||
"Content-Type: text/plain; charset=UTF-8\n" |
|||
"Content-Transfer-Encoding: \n" |
|||
"Plural-Forms: \n" |
|||
|
|||
#. module: pos_cash_move_reason |
|||
#: code:addons/pos_cash_move_reason/wizard/pos_box.py:36 |
|||
#, python-format |
|||
msgid "Description" |
|||
msgstr "Description" |
|||
|
|||
#. module: pos_cash_move_reason |
|||
#: field:cash.box.in,product_id:0 |
|||
#: field:cash.box.out,product_id:0 |
|||
msgid "Reason" |
|||
msgstr "Motif" |
|||
|
|||
#. module: pos_cash_move_reason |
|||
#: code:addons/pos_cash_move_reason/wizard/pos_box.py:84 |
|||
#, python-format |
|||
msgid "You have to define an\n" |
|||
" expense account on the related product" |
|||
msgstr "Vous devez définir un\n" |
|||
" compte de charge sur le produit lié" |
|||
|
|||
#. module: pos_cash_move_reason |
|||
#: code:addons/pos_cash_move_reason/wizard/pos_box.py:60 |
|||
#, python-format |
|||
msgid "You have to define an\n" |
|||
" income account on the related product" |
|||
msgstr "Vous devez définir un\n" |
|||
" compte de produit sur le produit lié" |
|||
|
@ -0,0 +1,43 @@ |
|||
# Translation of Odoo Server. |
|||
# This file contains the translation of the following modules: |
|||
# * pos_cash_move_reason |
|||
# |
|||
msgid "" |
|||
msgstr "" |
|||
"Project-Id-Version: Odoo Server 8.0\n" |
|||
"Report-Msgid-Bugs-To: \n" |
|||
"POT-Creation-Date: 2016-04-12 11:09+0000\n" |
|||
"PO-Revision-Date: 2016-04-12 11:09+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_cash_move_reason |
|||
#: code:addons/pos_cash_move_reason/wizard/pos_box.py:36 |
|||
#, python-format |
|||
msgid "Description" |
|||
msgstr "" |
|||
|
|||
#. module: pos_cash_move_reason |
|||
#: field:cash.box.in,product_id:0 |
|||
#: field:cash.box.out,product_id:0 |
|||
msgid "Reason" |
|||
msgstr "" |
|||
|
|||
#. module: pos_cash_move_reason |
|||
#: code:addons/pos_cash_move_reason/wizard/pos_box.py:84 |
|||
#, python-format |
|||
msgid "You have to define an\n" |
|||
" expense account on the related product" |
|||
msgstr "" |
|||
|
|||
#. module: pos_cash_move_reason |
|||
#: code:addons/pos_cash_move_reason/wizard/pos_box.py:60 |
|||
#, python-format |
|||
msgid "You have to define an\n" |
|||
" income account on the related product" |
|||
msgstr "" |
|||
|
After Width: 128 | Height: 128 | Size: 9.2 KiB |
After Width: 903 | Height: 275 | Size: 24 KiB |
@ -0,0 +1,5 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2015 ACSONE SA/NV (<http://acsone.eu>) |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
from . import test_pos_cash_move_reason |
@ -0,0 +1,106 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2015 ACSONE SA/NV (<http://acsone.eu>) |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
from openerp.tests import common |
|||
|
|||
|
|||
class TestPosCashMoveReason(common.TransactionCase): |
|||
|
|||
def setUp(self): |
|||
super(TestPosCashMoveReason, self).setUp() |
|||
self.pos_session_obj = self.env['pos.session'] |
|||
self.aml_obj = self.env['account.move.line'] |
|||
self.cash_in_obj = self.env['cash.box.in'] |
|||
self.cash_out_obj = self.env['cash.box.out'] |
|||
self.cash_move_reason_obj = self.env['product.template'] |
|||
self.main_config = self.env.ref('point_of_sale.pos_config_main') |
|||
self.cash_journal = self.env.ref('account.cash_journal') |
|||
self.income_account = self.env.ref('account.o_income') |
|||
self.expense_account = self.env.ref('account.a_expense') |
|||
|
|||
def test01(self): |
|||
# I create one move reason |
|||
vals = {'name': 'Miscellaneous income', |
|||
'property_account_income': self.income_account.id, |
|||
'income_pdt': True} |
|||
move_reason = self.cash_move_reason_obj.create(vals) |
|||
# I set cash control on cash journal |
|||
self.cash_journal.cash_control = True |
|||
# I create and open a new session |
|||
self.session_01 = self.pos_session_obj.create( |
|||
{'config_id': self.main_config.id}) |
|||
ctx = self.env.context.copy() |
|||
# context is updated in open_cb |
|||
# -> Need to call with old api to give unfrozen context |
|||
self.registry['pos.session'].open_cb( |
|||
self.cr, self.uid, [self.session_01.id], context=ctx) |
|||
ctx['active_ids'] = self.session_01.id |
|||
ctx['active_model'] = self.session_01._name |
|||
# I put the session in validation control |
|||
self.session_01.signal_workflow('cashbox_control') |
|||
ctx['active_ids'] = self.session_01.id |
|||
ctx['active_model'] = self.session_01._name |
|||
# I create a cash in |
|||
cash_in = self.cash_in_obj.with_context(ctx).create( |
|||
{'name': 'Initialization', |
|||
'product_id': move_reason.id, |
|||
'amount': 500.0}) |
|||
cash_in.with_context(ctx).run() |
|||
# I close the session |
|||
self.session_01.signal_workflow('close') |
|||
# I get the statement from the session |
|||
statement = self.env['account.bank.statement'].search( |
|||
[('pos_session_id', '=', self.session_01.id), |
|||
('journal_id', '=', self.cash_journal.id)]) |
|||
# I get all move lines of this statement |
|||
move_line_ids = statement.move_line_ids.ids |
|||
move_line = self.env['account.move.line'].search( |
|||
[('account_id', '=', self.income_account.id), |
|||
('credit', '=', 500.0), |
|||
('id', 'in', move_line_ids)]) |
|||
# I check the created move line from the cash in |
|||
self.assertEquals(len(move_line.ids), 1) |
|||
|
|||
def test02(self): |
|||
# I create one move reason |
|||
vals = {'name': 'Miscellaneous expense', |
|||
'property_account_expense': self.expense_account.id, |
|||
'expense_pdt': True} |
|||
move_reason = self.cash_move_reason_obj.create(vals) |
|||
# I set cash control on cash journal |
|||
self.cash_journal.cash_control = True |
|||
# I create and open a new session |
|||
self.session_01 = self.pos_session_obj.create( |
|||
{'config_id': self.main_config.id}) |
|||
ctx = self.env.context.copy() |
|||
# context is updated in open_cb |
|||
# -> Need to call with old api to give unfrozen context |
|||
self.registry['pos.session'].open_cb( |
|||
self.cr, self.uid, [self.session_01.id], context=ctx) |
|||
ctx['active_ids'] = self.session_01.id |
|||
ctx['active_model'] = self.session_01._name |
|||
# I put the session in validation control |
|||
self.session_01.signal_workflow('cashbox_control') |
|||
ctx['active_ids'] = self.session_01.id |
|||
ctx['active_model'] = self.session_01._name |
|||
# I create a cash out |
|||
cash_out = self.cash_out_obj.with_context(ctx).create( |
|||
{'name': 'Miscellaneous expense', |
|||
'product_id': move_reason.id, |
|||
'amount': 500.0}) |
|||
cash_out.with_context(ctx).run() |
|||
# I close the session |
|||
self.session_01.signal_workflow('close') |
|||
# I get the statement from the session |
|||
statement = self.env['account.bank.statement'].search( |
|||
[('pos_session_id', '=', self.session_01.id), |
|||
('journal_id', '=', self.cash_journal.id)]) |
|||
# I get all move lines of this statement |
|||
move_line_ids = statement.move_line_ids.ids |
|||
move_line = self.env['account.move.line'].search( |
|||
[('account_id', '=', self.expense_account.id), |
|||
('debit', '=', 500.0), |
|||
('id', 'in', move_line_ids)]) |
|||
# I check the created move line from the cash in |
|||
self.assertEquals(len(move_line.ids), 1) |
@ -0,0 +1,5 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2015 ACSONE SA/NV (<http://acsone.eu>) |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
from . import pos_box |
@ -0,0 +1,86 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2015 ACSONE SA/NV (<http://acsone.eu>) |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
from openerp import api, exceptions, fields, _ |
|||
from openerp.addons.point_of_sale.wizard.pos_box import PosBox |
|||
|
|||
from lxml import etree |
|||
import simplejson |
|||
|
|||
|
|||
class PosBoxCashMoveReason(PosBox): |
|||
_register = False |
|||
|
|||
@api.onchange('product_id') |
|||
def onchange_reason(self): |
|||
for record in self: |
|||
if record.product_id.id: |
|||
record.name = record.product_id.name |
|||
|
|||
@api.model |
|||
def fields_view_get(self, view_id=None, view_type='form', |
|||
toolbar=False, submenu=False): |
|||
res = super(PosBoxCashMoveReason, self).fields_view_get( |
|||
view_id=view_id, view_type=view_type, toolbar=toolbar, |
|||
submenu=submenu) |
|||
doc = etree.XML(res['arch']) |
|||
if self.env.context.get('active_model', '') != 'pos.session': |
|||
for node in doc.xpath("//field[@name='product_id']"): |
|||
modifiers = {'invisible': True, 'required': False} |
|||
node.set('invisible', '1') |
|||
node.set('required', '0') |
|||
node.set('modifiers', simplejson.dumps(modifiers)) |
|||
else: |
|||
for node in doc.xpath("//field[@name='name']"): |
|||
node.set('string', _('Description')) |
|||
res['arch'] = etree.tostring(doc) |
|||
return res |
|||
|
|||
|
|||
class PosBoxIn(PosBoxCashMoveReason): |
|||
_inherit = 'cash.box.in' |
|||
|
|||
product_id = fields.Many2one( |
|||
comodel_name='product.template', string='Reason', |
|||
domain="[('income_pdt', '=', True)]") |
|||
|
|||
@api.model |
|||
def _compute_values_for_statement_line(self, box, record): |
|||
values = super(PosBoxIn, self)._compute_values_for_statement_line( |
|||
box, record) |
|||
if self.env.context.get('active_model', '') == 'pos.session': |
|||
if box.product_id.id: |
|||
product = box.product_id |
|||
account_id = product.property_account_income.id or\ |
|||
product.categ_id.property_account_income_categ.id |
|||
if account_id: |
|||
values['account_id'] = account_id |
|||
else: |
|||
raise exceptions.Warning(_("""You have to define an |
|||
income account on the related product""")) |
|||
return values |
|||
|
|||
|
|||
class PosBoxOut(PosBoxCashMoveReason): |
|||
_inherit = 'cash.box.out' |
|||
|
|||
product_id = fields.Many2one( |
|||
comodel_name='product.template', string='Reason', |
|||
domain="[('expense_pdt', '=', True)]") |
|||
|
|||
@api.model |
|||
def _compute_values_for_statement_line(self, box, record): |
|||
values = super(PosBoxOut, self)._compute_values_for_statement_line( |
|||
box, record) |
|||
if self.env.context.get('active_model', '') == 'pos.session': |
|||
if box.product_id.id: |
|||
product = box.product_id |
|||
account_id = product.property_account_expense.id or\ |
|||
product.categ_id.property_account_expense_categ.id |
|||
if account_id: |
|||
values['account_id'] = account_id |
|||
else: |
|||
raise exceptions.Warning(_("""You have to define an |
|||
expense account on the related product""")) |
|||
return values |
@ -0,0 +1,26 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<openerp> |
|||
<data> |
|||
<record model="ir.ui.view" id="cash_box_in_form"> |
|||
<field name="name">cash.box.in.form</field> |
|||
<field name="model">cash.box.in</field> |
|||
<field name="inherit_id" ref="account.cash_box_in_form" /> |
|||
<field name="arch" type="xml"> |
|||
<xpath expr="//field[@name='name']" position="before"> |
|||
<field name="product_id" required="1" class="oe_inline" /> |
|||
</xpath> |
|||
</field> |
|||
</record> |
|||
|
|||
<record model="ir.ui.view" id="cash_box_out_form"> |
|||
<field name="name">cash.box.out.form</field> |
|||
<field name="model">cash.box.out</field> |
|||
<field name="inherit_id" ref="account.cash_box_out_form" /> |
|||
<field name="arch" type="xml"> |
|||
<xpath expr="//field[@name='name']" position="before"> |
|||
<field name="product_id" required="1" class="oe_inline"/> |
|||
</xpath> |
|||
</field> |
|||
</record> |
|||
</data> |
|||
</openerp> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue