Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

11.0 POS multi session: restore unpaid orders #1307

Open
wants to merge 8 commits into
base: 11.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 67 additions & 27 deletions pos_multi_session/models/pos_multi_session_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
# License MIT (https://opensource.org/licenses/MIT).

import logging
from odoo import api, models, fields, _
from odoo.exceptions import UserError
import datetime
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT

from odoo import api, fields, models

_logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -60,42 +63,74 @@ def _search_current_session_state(self, operator, value):
else:
return [("id", "in", [])]

@api.multi
def open_ui(self):
res = super(PosConfig, self).open_ui()
active_sessions = self.env['pos.session'].search(
[('state', '!=', 'closed'), ('config_id.multi_session_id', '=', self.multi_session_id.id)])
if len(active_sessions) == 1 and active_sessions.id == self.current_session_id.id and self.multi_session_id.load_unpaid_orders:
orders = self.multi_session_id.get_unpaid_ms_orders()
if orders:
orders.write({
'state': 'draft',
'run_ID': self.multi_session_id.run_ID
})
return res


class PosMultiSession(models.Model):
_name = "pos.multi_session"

name = fields.Char("Name")
multi_session_active = fields.Boolean(
string="Active",
help="Select the checkbox to enable synchronization for POSes",
default=True,
)
pos_ids = fields.One2many(
"pos.config", "multi_session_id", string="POSes in Multi-session"
)
order_ID = fields.Integer(
string="Order number",
default=0,
help="Current Order Number shared across all POS in Multi Session",
)
sync_server = fields.Char("Sync Server", default="")
run_ID = fields.Integer(
string="Running count",
default=1,
help="Number of Multi-session starts. "
"It's incremented each time the last session in Multi-session is closed. "
"It's used to prevent synchronization of old orders",
)
fiscal_position_ids = fields.Many2many(
"account.fiscal.position", string="Fiscal Positions", ondelete="restrict"
)
name = fields.Char('Name')
multi_session_active = fields.Boolean(string="Active", help="Select the checkbox to enable synchronization for POSes", default=True)
pos_ids = fields.One2many('pos.config', 'multi_session_id', string='POSes in Multi-session')
order_ID = fields.Integer(string="Order number", default=0, help="Current Order Number shared across all POS in Multi Session")
sync_server = fields.Char('Sync Server', default='')
run_ID = fields.Integer(string="Running count", default=1,
help="Number of Multi-session starts. "
"It's incremented each time the last session in Multi-session is closed. "
"It's used to prevent synchronization of old orders")
fiscal_position_ids = fields.Many2many('account.fiscal.position', string='Fiscal Positions', ondelete="restrict")
load_unpaid_orders = fields.Boolean(string="Load Unpaid Orders", default=False,
help="Allows you to load unpaid orders to POS."
"Please close all POS sessions before loading unpaid orders.")
load_orders_of_last_n_days = fields.Boolean("Unpaid Orders of last 'n' days", default=False,
help="if the setting is disabled then all orders will be loaded to POS")
number_of_days = fields.Integer("Number of days", default=0, help='0 - load orders of current day')
company_id = fields.Many2one(
"res.company",
string="Company",
required=True,
default=lambda self: self.env.user.company_id,
)

@api.constrains('load_unpaid_orders')
def _check_load_unpaid_orders(self):
if self.load_unpaid_orders:
active_sessions = self.env['pos.session'].search(
[('state', '!=', 'closed'), ('config_id.multi_session_id', '=', self.id)])
if active_sessions:
raise UserError(_("Please close all POSes for this multi-session for load unpaid Orders."))

@api.constrains('number_of_days')
def _check_number_of_days(self):
if self.load_unpaid_orders and self.load_orders_of_last_n_days and self.number_of_days < 0:
raise UserError(_('The number of days should not be negative.'))

@api.multi
def get_unpaid_ms_orders(self):
self.ensure_one()
pos_multi_session_sync = self.env['pos_multi_session_sync.multi_session'].search([('multi_session_ID', '=', self.id)])
if self.load_orders_of_last_n_days:
limit_date = datetime.datetime.utcnow() - datetime.timedelta(days=self.number_of_days)
limit_date_str = datetime.datetime.strftime(limit_date, DEFAULT_SERVER_DATE_FORMAT + ' 00:00:00')
return self.env['pos_multi_session_sync.order'].search([('multi_session_ID', 'in', pos_multi_session_sync.ids),
('state', '=', 'unpaid'),
('write_date', '>=', limit_date_str)])

return self.env['pos_multi_session_sync.order'].search([("multi_session_ID", "=", pos_multi_session_sync.multi_session_ID),
('state', '=', 'unpaid')])

@api.multi
def action_set_default_multi_session(self):
"""
Expand Down Expand Up @@ -137,5 +172,10 @@ def action_pos_session_close(self):
if len(active_sessions) == 0:
self.config_id.multi_session_id.sudo().write({"order_ID": 0})
run_ID = self.config_id.multi_session_id.run_ID + 1
self.config_id.multi_session_id.sudo().write({"run_ID": run_ID})
self.config_id.multi_session_id.sudo().write({'run_ID': run_ID})
pos_multi_session_sync = self.env['pos_multi_session_sync.multi_session'].search(
[('multi_session_ID', '=', self.config_id.multi_session_id.id)])
orders = self.env['pos_multi_session_sync.order'].search([('multi_session_ID', '=', pos_multi_session_sync.multi_session_ID),
('state', '=', 'draft')])
orders.write({'state': 'unpaid'})
return res
23 changes: 8 additions & 15 deletions pos_multi_session/multi_session_view.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,14 @@
<field name="name" />
</h1>
<group string="Settings">
<field
name="pos_ids"
widget="many2many_tags"
domain="[('current_session_state', '!=', 'opened')]"
options="{'not_delete': True}"
/>
<field name="multi_session_active" />
<field name="sync_server" placeholder="http://yourhost" />
<field
name="fiscal_position_ids"
widget="many2many_tags"
options="{'not_delete': True}"
/>
<field name="company_id" groups="base.group_multi_company" />
<field name="order_ID" readonly="1" />
<field name="pos_ids" widget="many2many_tags" domain="[('current_session_state', '!=', 'opened')]" options="{'not_delete': True}"/>
<field name="multi_session_active"/>
<field name="sync_server" placeholder="http://yourhost"/>
<field name="fiscal_position_ids" widget="many2many_tags" options="{'not_delete': True}"/>
<field name="order_ID" readonly="1"/>
<field name="load_unpaid_orders"/>
<field name="load_orders_of_last_n_days" attrs="{'invisible':[('load_unpaid_orders', '=', False)]}"/>
<field name="number_of_days" attrs="{'invisible':['|', ('load_unpaid_orders', '=', False), ('load_orders_of_last_n_days', '=', False)]}"/>
</group>
<group>
<p
Expand Down
71 changes: 71 additions & 0 deletions pos_multi_session/views/pos_multi_session_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,77 @@
/>
</xpath>
</template>

<record id="view_pos_multi_session_sync_order_form" model="ir.ui.view">
<field name="name">pos_multi_session_sync.order.form</field>
<field name="model">pos_multi_session_sync.order</field>
<field name="arch" type="xml">
<form string="POS Multi-Session Sync Orders" create="false" edit="false" delete="false">
<header>
<button name="action_pos_multi_session_restore_order" string="Restore" type="object" states="deleted"/>
<field name="state" widget="statusbar" statusbar_visible="draft,paid,deleted" />
</header>
<sheet>
<group col="4" colspan="4">
<field name="order_uid"/>
<field name="write_date"/>
<field name="revision_ID"/>
<field name="multi_session_ID"/>
<field name="pos_session_ID"/>
<field name="run_ID"/>
</group>
<group>
<field name="order"/>
</group>
</sheet>
</form>
</field>
</record>

<record id="view_pos_multi_session_sync_order_tree" model="ir.ui.view">
<field name="name">pos_multi_session_sync.order.tree</field>
<field name="model">pos_multi_session_sync.order</field>
<field name="arch" type="xml">
<tree create="0">
<field name="order_uid"/>
<field name="write_date"/>
<field name="state"/>
</tree>
</field>
</record>

<record id="view_pos_multi_session_sync_order_filter" model="ir.ui.view">
<field name="name">pos_multi_session_sync.order.filter</field>
<field name="model">pos_multi_session_sync.order</field>
<field name="arch" type="xml">
<search string="Search POS Multi-Session Order">
<field name="state"/>
<filter name="paid" string="Paid" domain="[('state','=','paid')]"/>
<filter name="new" string="New" domain="[('state','=','draft')]"/>
<filter name="deleted" string="Deleted" domain="[('state','=','deleted')]"/>
<filter name="unpaid" string="Unpaid" domain="[('state','=','unpaid')]"/>
</search>
</field>
</record>

<record id="action_pos_multi_session_sync_order" model="ir.actions.act_window">
<field name="name">Multi Session Orders</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">pos_multi_session_sync.order</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_pos_multi_session_sync_order_tree"/>
<field name="view_mode">tree,form</field>
<field name="context">{'search_default_deleted': 1}
</field>
</record>

<menuitem id="menu_multi_session_orders"
parent="point_of_sale.menu_point_of_sale"
action="action_pos_multi_session_sync_order"
sequence="99"
groups="base.group_no_one"/>


<record model="ir.ui.view" id="view_pos_config_form">
<field name="name">pos.config.form.view.inherit</field>
<field name="model">pos.config</field>
Expand Down
90 changes: 39 additions & 51 deletions pos_multi_session_sync/models/pos_multi_session_sync_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,11 @@ def on_update_message(self, message):
@api.multi
def prepare_new_session(self, message):
self.ensure_one()
run_ID = message["data"]["run_ID"]
self.write({"run_ID": run_ID})
old_orders = self.env["pos_multi_session_sync.order"].search(
[
("multi_session_ID", "=", self.multi_session_ID),
("state", "=", "draft"),
("run_ID", "<", run_ID),
]
)
if old_orders:
old_orders.write({"state": "unpaid"})
self.write({"order_ID": 0})
run_ID = message['data']['run_ID']
self.write({
'run_ID': run_ID,
'order_ID': 0
})

@api.multi
def check_order_revision(self, message, order):
Expand Down Expand Up @@ -168,17 +161,10 @@ def set_order(self, message):
run_ID = order.run_ID or message["data"]["run_ID"] or False

if revision == "nonce":
return (False, {"action": ""})
elif not revision or (order and order.state == "deleted"):
_logger.debug("Revision error %s %s", order_uid, order.state)
return (
False,
{
"action": "revision_error",
"order_uid": order_uid,
"state": order.state,
},
)
return (False, {'action': ''})
elif not revision or (order and (order.state == 'deleted' or order.state == 'paid')):
_logger.debug('Revision error %s %s', order_uid, order.state)
return (False, {'action': 'revision_error', 'order_uid': order_uid, 'state': order.state})

if order: # order already exists
message = self.set_changes(message, order)
Expand Down Expand Up @@ -297,18 +283,16 @@ def remove_order(self, message):
order, order_data = self.set_order(order_data)
order_uid = order.order_uid

if order.state != "deleted":
if order.state not in ['deleted', 'paid']:
revision = self.check_order_revision(message, order)
if not revision:
return {"action": "revision_error", "order_uid": order_uid}
return {'action': 'revision_error', 'order_uid': order_uid}

state = 'paid' if message['data']['finalized'] else 'deleted'
if order:
order.state = "deleted"
_logger.debug(
"Remove Order: %s Finalized: %s Revision: %s",
order_uid,
message["data"]["finalized"],
message["data"]["revision_ID"],
)
order.state = state
_logger.debug('Remove Order: %s Finalized: %s Revision: %s',
order_uid, message['data']['finalized'], message['data']['revision_ID'])
self.broadcast_message(message)
return {"order_ID": self.order_ID}

Expand Down Expand Up @@ -365,26 +349,30 @@ def broadcast_message(self, message):


class PosMultiSessionSyncOrder(models.Model):
_name = "pos_multi_session_sync.order"
_name = 'pos_multi_session_sync.order'
_order = 'write_date desc'
_rec_name = 'order_uid'

order = fields.Text("Order JSON format")
nonce = fields.Char("Random nonce")
order_uid = fields.Char(index=True)
state = fields.Selection(
[("draft", "Draft"), ("deleted", "Deleted"), ("unpaid", "Unpaid and removed")],
default="draft",
index=True,
)
revision_ID = fields.Integer(
default=1, string="Revision", help="Number of updates received from clients"
)
multi_session_ID = fields.Integer(default=0, string="Multi session")
pos_session_ID = fields.Integer(index=True, default=0, string="POS session")
run_ID = fields.Integer(
index=True,
string="Running count",
default=1,
help="Number of Multi-session starts. "
"It's incremented each time the last session in Multi-session is closed. "
"It's used to prevent synchronization of old orders",
)
state = fields.Selection([('draft', 'Draft'), ('deleted', 'Deleted'), ('unpaid', 'Unpaid and removed'),
('paid', 'Paid')], default='draft', index=True)
revision_ID = fields.Integer(default=1, string="Revision", help="Number of updates received from clients")
multi_session_ID = fields.Integer(default=0, string='Multi session')
pos_session_ID = fields.Integer(index=True, default=0, string='POS session')
run_ID = fields.Integer(index=True, string="Running count", default=1,
help="Number of Multi-session starts. "
"It's incremented each time the last session in Multi-session is closed. "
"It's used to prevent synchronization of old orders")

@api.multi
def action_pos_multi_session_restore_order(self):
for r in self:
# sync_ms = self.env['pos_multi_session_sync.multi_session'].browse(r.multi_session_ID)
sync_ms = self.env['pos_multi_session_sync.multi_session'].search([('multi_session_ID', '=', r.multi_session_ID)])
r.write({
'state': 'draft',
'run_ID': sync_ms.run_ID
})
# TODO: send the order to POSes via bus after restore