From b5b0d36b31606e6c462a83080c66ec06b326ed45 Mon Sep 17 00:00:00 2001
From: Martin Trigaux <mat@odoo.com>
Date: Wed, 28 Sep 2016 15:49:24 +0200
Subject: [PATCH] [ADD] point_of_sale: differentiate the sale and invoice
 journal

Using the same journal for both the session closing and the invoices generated
from the PoS may be problematic as they share the same sequence.
In such case, gaps may appears in the invoice numbers (as the sequence is on the
account.move, closing a session increases the sequence by one).

cf opw-685660
Fixes 13242
---
 addons/point_of_sale/data/point_of_sale_data.xml |  9 +++++++++
 addons/point_of_sale/models/pos_config.py        | 16 ++++++++++++++++
 addons/point_of_sale/models/pos_order.py         |  2 +-
 addons/point_of_sale/models/pos_session.py       |  9 ++++++---
 addons/point_of_sale/tests/test_frontend.py      |  6 ++++--
 addons/point_of_sale/views/pos_config_view.xml   |  1 +
 6 files changed, 37 insertions(+), 6 deletions(-)

diff --git a/addons/point_of_sale/data/point_of_sale_data.xml b/addons/point_of_sale/data/point_of_sale_data.xml
index aba585a2b5ab..f2c82edc99aa 100644
--- a/addons/point_of_sale/data/point_of_sale_data.xml
+++ b/addons/point_of_sale/data/point_of_sale_data.xml
@@ -51,6 +51,15 @@
             <field name="default_code">MISC</field>
             <field name="image" type="base64" file="point_of_sale/static/img/product_product_49-image.jpg"/>
         </record>
+
+        <record id="pos_sale_journal" model="account.journal">
+            <field name="name">POS Sale Journal</field>
+            <field name="code">POSS</field>
+            <field name="type">sale</field>
+            <!-- avoid being selected as default journal -->
+            <field name="sequence">20</field>
+        </record>
+
     </data>
 </odoo>
 
diff --git a/addons/point_of_sale/models/pos_config.py b/addons/point_of_sale/models/pos_config.py
index ad25692e1e3b..07bd2f840510 100644
--- a/addons/point_of_sale/models/pos_config.py
+++ b/addons/point_of_sale/models/pos_config.py
@@ -30,6 +30,12 @@ class PosConfig(models.Model):
     _name = 'pos.config'
 
     def _default_sale_journal(self):
+        journal = self.env.ref('point_of_sale.pos_sale_journal', raise_if_not_found=False)
+        if journal and journal.company_id == self.env.user.company_id:
+            return journal
+        return self._default_invoice_journal()
+
+    def _default_invoice_journal(self):
         return self.env['account.journal'].search([('type', '=', 'sale'), ('company_id', '=', self.env.user.company_id.id)], limit=1)
 
     def _default_pricelist(self):
@@ -61,6 +67,11 @@ class PosConfig(models.Model):
         domain=[('type', '=', 'sale')],
         help="Accounting journal used to post sales entries.",
         default=_default_sale_journal)
+    invoice_journal_id = fields.Many2one(
+        'account.journal', string='Invoice Journal',
+        domain=[('type', '=', 'sale')],
+        help="Accounting journal used to create invoices.",
+        default=_default_invoice_journal)
     currency_id = fields.Many2one('res.currency', compute='_compute_currency', string="Currency")
     iface_cashdrawer = fields.Boolean(string='Cashdrawer', help="Automatically open the cashdrawer")
     iface_payment_terminal = fields.Boolean(string='Payment Terminal', help="Enables Payment Terminal integration")
@@ -160,6 +171,11 @@ class PosConfig(models.Model):
         if self.journal_id and self.journal_id.company_id.id != self.company_id.id:
             raise UserError(_("The company of the sale journal is different than the one of point of sale"))
 
+    @api.constrains('company_id', 'invoice_journal_id')
+    def _check_company_journal(self):
+        if self.invoice_journal_id and self.invoice_journal_id.company_id.id != self.company_id.id:
+            raise UserError(_("The invoice journal and the point of sale must belong to the same company"))
+
     @api.constrains('company_id', 'journal_ids')
     def _check_company_payment(self):
         if self.env['account.journal'].search_count([('id', 'in', self.journal_ids.ids), ('company_id', '!=', self.company_id.id)]):
diff --git a/addons/point_of_sale/models/pos_order.py b/addons/point_of_sale/models/pos_order.py
index b069d627a766..ca3d71f665bd 100644
--- a/addons/point_of_sale/models/pos_order.py
+++ b/addons/point_of_sale/models/pos_order.py
@@ -160,7 +160,7 @@ class PosOrder(models.Model):
             'name': self.name,
             'origin': self.name,
             'account_id': self.partner_id.property_account_receivable_id.id,
-            'journal_id': self.sale_journal.id,
+            'journal_id': self.session_id.config_id.invoice_journal_id.id,
             'type': 'out_invoice',
             'reference': self.name,
             'partner_id': self.partner_id.id,
diff --git a/addons/point_of_sale/models/pos_session.py b/addons/point_of_sale/models/pos_session.py
index 942625d76ba8..ea0f8391bfef 100644
--- a/addons/point_of_sale/models/pos_session.py
+++ b/addons/point_of_sale/models/pos_session.py
@@ -144,10 +144,13 @@ class PosSession(models.Model):
         pos_config = self.env['pos.config'].browse(config_id)
         ctx = dict(self.env.context, company_id=pos_config.company_id.id)
         if not pos_config.journal_id:
-            jid = pos_config.with_context(ctx).default_get(['journal_id'])['journal_id']
-            if not jid:
+            default_journals = pos_config.with_context(ctx).default_get(['journal_id', 'invoice_journal_id'])
+            if (not default_journals.get('journal_id') or
+                    not default_journals.get('invoice_journal_id')):
                 raise UserError(_("Unable to open the session. You have to assign a sale journal to your point of sale."))
-            pos_config.with_context(ctx).sudo().write({'journal_id': jid})
+            pos_config.with_context(ctx).sudo().write({
+                'journal_id': default_journals['journal_id'],
+                'invoice_journal_id': default_journals['invoice_journal_id']})
         # define some cash journal if no payment method exists
         if not pos_config.journal_ids:
             Journal = self.env['account.journal']
diff --git a/addons/point_of_sale/tests/test_frontend.py b/addons/point_of_sale/tests/test_frontend.py
index c399c974677a..88fbc551bb76 100644
--- a/addons/point_of_sale/tests/test_frontend.py
+++ b/addons/point_of_sale/tests/test_frontend.py
@@ -42,8 +42,10 @@ class TestUi(odoo.tests.HttpCase):
 
         env['product.pricelist'].search([]).write(dict(currency_id=main_company.currency_id.id))
 
-        main_pos_config.journal_id = test_sale_journal
-        main_pos_config.write({'journal_ids': [(0, 0, {'name': 'Cash Journal - Test',
+        main_pos_config.write({
+            'journal_id': test_sale_journal.id,
+            'invoice_journal_id': test_sale_journal.id,
+            'journal_ids': [(0, 0, {'name': 'Cash Journal - Test',
                                                        'code': 'TSC',
                                                        'type': 'cash',
                                                        'company_id': main_company.id,
diff --git a/addons/point_of_sale/views/pos_config_view.xml b/addons/point_of_sale/views/pos_config_view.xml
index a50f40929a5e..f94f7905ccad 100644
--- a/addons/point_of_sale/views/pos_config_view.xml
+++ b/addons/point_of_sale/views/pos_config_view.xml
@@ -14,6 +14,7 @@
                         <field name="company_id" groups="base.group_multi_company"/>
                         <field name="pricelist_id" groups="product.group_sale_pricelist"/>
                         <field name="journal_id" widget="selection"/>
+                        <field name="invoice_journal_id" widget="selection"/>
                         <field name="group_by" groups="account.group_account_user"/>
                         <field name="barcode_nomenclature_id" />
                         <field name="sequence_id" readonly="1" groups="base.group_no_one"/>
-- 
GitLab