diff --git a/pos_session_pay_invoice/README.rst b/pos_session_pay_invoice/README.rst new file mode 100644 index 00000000..e8585e61 --- /dev/null +++ b/pos_session_pay_invoice/README.rst @@ -0,0 +1,56 @@ +.. image:: https://img.shields.io/badge/licence-LGPL--3-blue.svg + :alt: License: LGPL-3 + +======================== +Account cash Pay invoice +======================== + +This modules allows to pay an existing Supplier Invoice / Customer Refund, or +to collect payment for an existing Customer Invoice, using bank statements. + + +Usage +===== + +#. Go to *Accounting / Dashboard* and create and/or open an existing + bank statement. +#. Press the button **Pay Invoice** to pay a Supplier Invoice or a Customer + Refund. You will need to select the expected Journal +#. Select **Collect Payment from Invoice** in to receive a payment of an + existing Customer Invoice or a Supplier Refund. + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/repo/github-com-oca-pos-184 + + +Known issues / Roadmap +====================== + +* Cannot pay invoices in a different currency than that defined in the journal + associated to the payment method used to pay/collect payment. + + +Credits +======= + +Contributors +------------ + +* Enric Tobella + + +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 http://odoo-community.org. diff --git a/pos_session_pay_invoice/__init__.py b/pos_session_pay_invoice/__init__.py new file mode 100644 index 00000000..577a9637 --- /dev/null +++ b/pos_session_pay_invoice/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +from . import wizard diff --git a/pos_session_pay_invoice/__manifest__.py b/pos_session_pay_invoice/__manifest__.py new file mode 100644 index 00000000..6531bf39 --- /dev/null +++ b/pos_session_pay_invoice/__manifest__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2017 Creu Blanca +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +{ + 'name': 'POS Pay invoice', + 'version': '10.0.1.0.0', + 'category': 'Point Of Sale', + 'author': "Creu Blanca," + "Odoo Community Association (OCA)", + 'website': 'https://github.com/OCA/pos', + 'summary': 'Pay and receive invoices from PoS Session', + "license": "LGPL-3", + 'depends': [ + "point_of_sale", "account_cash_invoice" + ], + 'data': [ + "wizard/cash_invoice_out.xml", + "wizard/cash_invoice_in.xml", + "views/pos_session.xml", + "views/account_bank_statement.xml", + ], +} diff --git a/pos_session_pay_invoice/static/description/icon.png b/pos_session_pay_invoice/static/description/icon.png new file mode 100644 index 00000000..3a0328b5 Binary files /dev/null and b/pos_session_pay_invoice/static/description/icon.png differ diff --git a/pos_session_pay_invoice/tests/__init__.py b/pos_session_pay_invoice/tests/__init__.py new file mode 100644 index 00000000..510806cb --- /dev/null +++ b/pos_session_pay_invoice/tests/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +from . import test_pay_invoice diff --git a/pos_session_pay_invoice/tests/test_pay_invoice.py b/pos_session_pay_invoice/tests/test_pay_invoice.py new file mode 100644 index 00000000..4cd5a09a --- /dev/null +++ b/pos_session_pay_invoice/tests/test_pay_invoice.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Creu Blanca +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +from odoo.tests import common + + +class TestSessionPayInvoice(common.TransactionCase): + def setUp(self): + super(TestSessionPayInvoice, self).setUp() + self.company = self.env.ref('base.main_company') + partner = self.env.ref('base.partner_demo') + self.invoice_out = self.env['account.invoice'].create({ + 'company_id': self.company.id, + 'partner_id': partner.id, + 'date_invoice': '2016-03-12', + 'type': 'out_invoice', + }) + account = self.env['account.account'].create({ + 'code': 'test_cash_pay_invoice', + 'company_id': self.company.id, + 'name': 'Test', + 'user_type_id': self.env.ref( + 'account.data_account_type_revenue').id + }) + self.env['account.invoice.line'].create({ + 'product_id': self.env.ref('product.product_delivery_02').id, + 'invoice_id': self.invoice_out.id, + 'account_id': account.id, + 'name': 'Producto de prueba', + 'quantity': 1.0, + 'price_unit': 100.0, + }) + self.invoice_out._onchange_invoice_line_ids() + self.invoice_out.action_invoice_open() + self.invoice_out.number = '2999/99999' + self.invoice_in = self.env['account.invoice'].create({ + 'partner_id': partner.id, + 'company_id': self.company.id, + 'type': 'in_invoice', + 'date_invoice': '2016-03-12', + }) + self.env['account.invoice.line'].create({ + 'product_id': self.env.ref('product.product_delivery_02').id, + 'invoice_id': self.invoice_in.id, + 'name': 'Producto de prueba', + 'account_id': account.id, + 'quantity': 1.0, + 'price_unit': 100.0, + }) + self.invoice_in._onchange_invoice_line_ids() + self.invoice_in.action_invoice_open() + self.invoice_in.number = '2999/99999' + self.config = self.env.ref('point_of_sale.pos_config_main') + self.config.cash_control = True + + def test_pos_invoice(self): + self.config.open_session_cb() + session = self.config.current_session_id + self.assertIsNotNone(session.statement_ids) + session.action_pos_session_open() + in_invoice = self.env['cash.invoice.in'].with_context( + active_ids=session.ids, active_model='pos.session' + ).create({ + 'invoice_id': self.invoice_in.id, + 'amount': 100.0 + }) + in_invoice.run() + out_invoice = self.env['cash.invoice.out'].with_context( + active_ids=session.ids, active_model='pos.session' + ).create({ + 'invoice_id': self.invoice_out.id, + 'amount': 75.0 + }) + out_invoice.run() + box = self.env['cash.box.in'].with_context( + active_ids=session.ids, active_model='pos.session' + ).create({ + 'name': "Testing", + 'amount': 25.0 + }) + box.run() + session.action_pos_session_closing_control() + session.action_pos_session_closing_control() + self.assertEqual(self.invoice_out.residual, 25.) + self.assertEqual(self.invoice_in.residual, 0.) diff --git a/pos_session_pay_invoice/views/account_bank_statement.xml b/pos_session_pay_invoice/views/account_bank_statement.xml new file mode 100644 index 00000000..95b1170d --- /dev/null +++ b/pos_session_pay_invoice/views/account_bank_statement.xml @@ -0,0 +1,21 @@ + + + + + diff --git a/pos_session_pay_invoice/views/pos_session.xml b/pos_session_pay_invoice/views/pos_session.xml new file mode 100644 index 00000000..38e2e71d --- /dev/null +++ b/pos_session_pay_invoice/views/pos_session.xml @@ -0,0 +1,43 @@ + + + + pos.config.kanban.view + pos.config + + + + + + + + + pos.session.form.view + pos.session + + + + + + + + + diff --git a/pos_session_pay_invoice/wizard/__init__.py b/pos_session_pay_invoice/wizard/__init__.py new file mode 100644 index 00000000..030f06a1 --- /dev/null +++ b/pos_session_pay_invoice/wizard/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +from . import cash_invoice_in +from . import cash_invoice_out diff --git a/pos_session_pay_invoice/wizard/cash_invoice_in.py b/pos_session_pay_invoice/wizard/cash_invoice_in.py new file mode 100644 index 00000000..6c77fcdb --- /dev/null +++ b/pos_session_pay_invoice/wizard/cash_invoice_in.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2017 Creu Blanca +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +from odoo import api, models, _ +from odoo.exceptions import UserError + + +class CashInvoiceIn(models.TransientModel): + _inherit = 'cash.invoice.in' + + def default_company(self, active_model, active_ids): + if active_model == 'pos.session': + active = self.env[active_model].browse(active_ids) + return active[0].config_id.company_id + return super(CashInvoiceIn, self).default_company( + active_model, active_ids + ) + + def default_journals(self, active_model, active_ids): + if active_model == 'pos.session': + active = self.env[active_model].browse(active_ids) + if not active.cash_register_id: + raise UserError(_( + "There is no cash register for this Pos session" + )) + return active.cash_register_id.journal_id + return super(CashInvoiceIn, self).default_journals( + active_model, active_ids + ) + + def default_currency(self, active_model, active_ids): + if active_model == 'pos.session': + journal = self._default_journal() + if journal.currency_id: + return journal.currency_id + return super(CashInvoiceIn, self).default_currency( + active_model, active_ids + ) + + @api.multi + def run(self): + active_model = self.env.context.get('active_model', False) + active_ids = self.env.context.get('active_ids', False) + if active_model == 'pos.session': + bank_statements = [ + session.statement_ids.filtered( + lambda r: r.journal_id.id == self.journal_id.id + ) + for session in self.env[active_model].browse(active_ids) + ] + if not bank_statements: + raise UserError(_('Bank Statement was not found')) + return self._run(bank_statements) + else: + return super(CashInvoiceIn, self).run() diff --git a/pos_session_pay_invoice/wizard/cash_invoice_in.xml b/pos_session_pay_invoice/wizard/cash_invoice_in.xml new file mode 100644 index 00000000..fb1483cf --- /dev/null +++ b/pos_session_pay_invoice/wizard/cash_invoice_in.xml @@ -0,0 +1,12 @@ + + + + diff --git a/pos_session_pay_invoice/wizard/cash_invoice_out.py b/pos_session_pay_invoice/wizard/cash_invoice_out.py new file mode 100644 index 00000000..19bee735 --- /dev/null +++ b/pos_session_pay_invoice/wizard/cash_invoice_out.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2017 Creu Blanca +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +from odoo import api, models, _ +from odoo.exceptions import UserError + + +class CashInvoiceOut(models.TransientModel): + _inherit = 'cash.invoice.out' + + def default_company(self, active_model, active_ids): + if active_model == 'pos.session': + active = self.env[active_model].browse(active_ids) + return active[0].config_id.company_id + return super(CashInvoiceOut, self).default_company( + active_model, active_ids + ) + + def default_currency(self, active_model, active_ids): + if active_model == 'pos.session': + journal = self._default_journal() + if journal.currency_id: + return journal.currency_id + return super(CashInvoiceOut, self).default_currency( + active_model, active_ids + ) + + def default_journals(self, active_model, active_ids): + if active_model == 'pos.session': + active = self.env[active_model].browse(active_ids) + return self.env['account.journal'].browse( + [r.journal_id.id for r in active.statement_ids]) + return super(CashInvoiceOut, self).default_journals( + active_model, active_ids + ) + + @api.multi + def run(self): + active_model = self.env.context.get('active_model', False) + active_ids = self.env.context.get('active_ids', False) + if active_model == 'pos.session': + bank_statements = [ + session.statement_ids.filtered( + lambda r: r.journal_id.id == self.journal_id.id + ) + for session in self.env[active_model].browse(active_ids) + ] + if not bank_statements: + raise UserError(_('Bank Statement was not found')) + return self._run(bank_statements) + else: + return super(CashInvoiceOut, self).run() diff --git a/pos_session_pay_invoice/wizard/cash_invoice_out.xml b/pos_session_pay_invoice/wizard/cash_invoice_out.xml new file mode 100644 index 00000000..0af983ef --- /dev/null +++ b/pos_session_pay_invoice/wizard/cash_invoice_out.xml @@ -0,0 +1,12 @@ + + + +