Browse Source

Sep 09: [FIX] Bug fixed 'pos_kitchen_screen_odoo'

pull/397/merge
Risvana Cybro 2 weeks ago
parent
commit
e4b7f6367c
  1. 2
      pos_kitchen_screen_odoo/__manifest__.py
  2. 5
      pos_kitchen_screen_odoo/doc/RELEASE_NOTES.md
  3. 277
      pos_kitchen_screen_odoo/models/pos_orders.py
  4. BIN
      pos_kitchen_screen_odoo/static/description/assets/screenshots/pos12.png
  5. BIN
      pos_kitchen_screen_odoo/static/description/assets/screenshots/pos13.png
  6. BIN
      pos_kitchen_screen_odoo/static/description/assets/screenshots/pos14.png
  7. 90
      pos_kitchen_screen_odoo/static/description/index.html
  8. 5
      pos_kitchen_screen_odoo/static/src/js/fields_load.js
  9. 94
      pos_kitchen_screen_odoo/static/src/js/order_button.js
  10. 1
      pos_kitchen_screen_odoo/static/src/js/order_pay.js

2
pos_kitchen_screen_odoo/__manifest__.py

@ -21,7 +21,7 @@
############################################################################ ############################################################################
{ {
'name': 'POS Kitchen Screen', 'name': 'POS Kitchen Screen',
'version': '18.0.1.1.4', 'version': '18.0.1.2.0',
'category': 'Point Of Sale', 'category': 'Point Of Sale',
'summary': 'POS Kitchen Screen facilitates sending certain orders ' 'summary': 'POS Kitchen Screen facilitates sending certain orders '
'automatically to the kitchen.The POS Kitchen Screen allows for ' 'automatically to the kitchen.The POS Kitchen Screen allows for '

5
pos_kitchen_screen_odoo/doc/RELEASE_NOTES.md

@ -34,3 +34,8 @@
#### Version 18.0.1.1.4 #### Version 18.0.1.1.4
#### BUG FIX #### BUG FIX
-Fixed the issue where a completed kitchen order reverted to 'Cooking' status after the payment was processed. -Fixed the issue where a completed kitchen order reverted to 'Cooking' status after the payment was processed.
#### 03.09.2025
#### Version 18.0.1.2.0
#### BUG FIX
-Fixed the issue where, after completing an order and selecting the same floor again, the previously submitted order was duplicated in the POS order line.

277
pos_kitchen_screen_odoo/models/pos_orders.py

@ -56,16 +56,12 @@ class PosOrder(models.Model):
[('id', 'in', product_ids)]).mapped( [('id', 'in', product_ids)]).mapped(
'prepair_time_minutes') 'prepair_time_minutes')
vals['avg_prepare_time'] = max(prepare_times) vals['avg_prepare_time'] = max(prepare_times)
existing_order = self.search( existing_order = self.search(
[("pos_reference", "=", vals.get("pos_reference"))], limit=1) [("pos_reference", "=", vals.get("pos_reference"))], limit=1)
if existing_order: if existing_order:
continue continue
if not vals.get("order_status"): if not vals.get("order_status"):
vals["order_status"] = 'draft' vals["order_status"] = 'draft'
# Ensure name is always set
if not vals.get('name'): if not vals.get('name'):
if vals.get('order_id'): if vals.get('order_id'):
config = self.env['pos.order'].browse( config = self.env['pos.order'].browse(
@ -76,12 +72,9 @@ class PosOrder(models.Model):
else: else:
vals['name'] = self.env['ir.sequence'].next_by_code( vals['name'] = self.env['ir.sequence'].next_by_code(
'pos.order') or '/' 'pos.order') or '/'
processed_vals_to_create.append(vals) processed_vals_to_create.append(vals)
res = super().create( res = super().create(
processed_vals_to_create) if processed_vals_to_create else self.browse() processed_vals_to_create) if processed_vals_to_create else self.browse()
orders_to_notify = [] orders_to_notify = []
for order in res: for order in res:
kitchen_screen = self.env["kitchen.screen"].search( kitchen_screen = self.env["kitchen.screen"].search(
@ -95,14 +88,12 @@ class PosOrder(models.Model):
in order_line.product_id.pos_categ_ids): in order_line.product_id.pos_categ_ids):
order_line.is_cooking = True order_line.is_cooking = True
has_kitchen_items = True has_kitchen_items = True
if has_kitchen_items: if has_kitchen_items:
order.is_cooking = True order.is_cooking = True
order.order_ref = order.name # Set order_ref here order.order_ref = order.name # Set order_ref here
if order.order_status != 'draft': if order.order_status != 'draft':
order.order_status = 'draft' order.order_status = 'draft'
orders_to_notify.append(order) orders_to_notify.append(order)
self.env.cr.commit() self.env.cr.commit()
for order in orders_to_notify: for order in orders_to_notify:
message = { message = {
@ -115,107 +106,71 @@ class PosOrder(models.Model):
} }
channel = f'pos_order_created_{order.config_id.id}' channel = f'pos_order_created_{order.config_id.id}'
self.env["bus.bus"]._sendone(channel, "notification", message) self.env["bus.bus"]._sendone(channel, "notification", message)
return res return res
def write(self, vals): def write(self, vals):
"""Override write function for adding order status in vals""" """Override write function for adding order status in vals"""
original_statuses = {order.id: order.order_status for order in self} res = super(PosOrder, self).write(vals)
message = {
'res_model': self._name,
'message': 'pos_order_created'
}
self.env["bus.bus"]._sendone('pos_order_created', "notification",
message)
for order in self: for order in self:
if order.order_status == "waiting" and vals.get(
"order_status") != "ready":
vals["order_status"] = order.order_status
if vals.get("state") == "paid" and order.name == "/":
vals["name"] = self._compute_order_name()
kitchen_screen = self.env["kitchen.screen"].search( kitchen_screen = self.env["kitchen.screen"].search(
[("pos_config_id", "=", order.config_id.id)], limit=1 [("pos_config_id", "=", order.config_id.id)], limit=1
) )
if kitchen_screen: if kitchen_screen:
has_kitchen_items = False has_kitchen_items = False
for line_data in order.lines: for line in order.lines:
if line_data.product_id.pos_categ_ids and any( if line.product_id.pos_categ_ids and any(
cat.id in kitchen_screen.pos_categ_ids.ids cat.id in kitchen_screen.pos_categ_ids.ids
for cat in line_data.product_id.pos_categ_ids for cat in line.product_id.pos_categ_ids):
): if not line.is_cooking:
line.write({
'is_cooking': True,
'order_status': line.order_status or 'draft'
})
has_kitchen_items = True has_kitchen_items = True
break
# Update vals instead of direct assignment to avoid recursive write
if has_kitchen_items and not order.is_cooking: if has_kitchen_items and not order.is_cooking:
vals.update({ order.write({
'is_cooking': True, 'is_cooking': True,
'order_status': vals.get('order_status', 'order_status': order.order_status or 'draft'
'draft') if not order.order_status else order.order_status
}) })
elif not has_kitchen_items and order.is_cooking:
vals.update({'is_cooking': False})
# Send notification only if order_status changed
if has_kitchen_items and order.id in original_statuses and 'order_status' in vals:
if original_statuses[order.id] != vals.get('order_status'):
message = { message = {
'res_model': self._name, 'res_model': self._name,
'message': 'pos_order_updated', 'message': 'pos_order_updated',
'order_id': order.id, 'order_id': order.id,
'config_id': order.config_id.id, 'config_id': order.config_id.id,
'new_status': vals.get('order_status') 'lines': order.lines.read([
'id', 'product_id', 'qty', 'order_status', 'is_cooking'
])
} }
channel = f'pos_order_created_{order.config_id.id}' channel = f'pos_order_created_{order.config_id.id}'
self.env["bus.bus"]._sendone(channel, "notification", self.env["bus.bus"]._sendone(channel, "notification", message)
message) return res
return super(PosOrder, self).write(vals)
@api.model @api.model
def get_details(self, shop_id, *args, **kwargs): def get_details(self, shop_id, *args, **kwargs):
"""Method to fetch kitchen orders for display on the kitchen screen.""" """Method to fetch kitchen orders for display on the kitchen screen."""
kitchen_screen = self.env["kitchen.screen"].sudo().search( kitchen_screen = self.env["kitchen.screen"].sudo().search(
[("pos_config_id", "=", shop_id)]) [("pos_config_id", "=", shop_id)])
if not kitchen_screen: if not kitchen_screen:
return {"orders": [], "order_lines": []} return {"orders": [], "order_lines": []}
pos_orders = self.env["pos.order"].search([ pos_orders = self.env["pos.order"].search([
("is_cooking", "=", True), ("is_cooking", "=", True),
("config_id", "=", shop_id), ("config_id", "=", shop_id),
("state", "not in", ["cancel", "paid"]), ("state", "not in", ["cancel"]),
("order_status", "!=", "cancel"), ("order_status", "in", ["draft", "waiting", "ready"])
"|", "|",
("order_status", "=", "draft"),
("order_status", "=", "waiting"),
("order_status", "=", "ready")
], order="date_order") ], order="date_order")
# Additional filtering to exclude paid orders with 'ready' status
pos_orders = pos_orders.filtered(lambda order: not (
order.state == "paid" and order.order_status == "ready"))
pos_lines = pos_orders.lines.filtered( pos_lines = pos_orders.lines.filtered(
lambda line: line.is_cooking and any( lambda line: line.is_cooking and any(
categ.id in kitchen_screen.pos_categ_ids.ids categ.id in kitchen_screen.pos_categ_ids.ids
for categ in line.product_id.pos_categ_ids for categ in line.product_id.pos_categ_ids
) )
) )
values = {"orders": pos_orders.read(), "order_lines": pos_lines.read()} values = {"orders": pos_orders.read(), "order_lines": pos_lines.read()}
user_tz_str = self.env.user.tz or 'UTC' user_tz_str = self.env.user.tz or 'UTC'
user_tz = pytz.timezone(user_tz_str) user_tz = pytz.timezone(user_tz_str)
utc = pytz.utc utc = pytz.utc
for value in values['orders']: for value in values['orders']:
if value.get('table_id'): if value.get('table_id'):
value['floor'] = value['table_id'][1].split(',')[0].strip() value['floor'] = value['table_id'][1].split(',')[0].strip()
date_str = value['date_order'] date_str = value['date_order']
try: try:
if isinstance(date_str, str): if isinstance(date_str, str):
@ -223,7 +178,6 @@ class PosOrder(models.Model):
utc_dt = utc.localize(utc_dt) utc_dt = utc.localize(utc_dt)
else: else:
utc_dt = utc.localize(value['date_order']) utc_dt = utc.localize(value['date_order'])
local_dt = utc_dt.astimezone(user_tz) local_dt = utc_dt.astimezone(user_tz)
value['hour'] = local_dt.hour value['hour'] = local_dt.hour
value['formatted_minutes'] = f"{local_dt.minute:02d}" value['formatted_minutes'] = f"{local_dt.minute:02d}"
@ -232,13 +186,11 @@ class PosOrder(models.Model):
value['hour'] = 0 value['hour'] = 0
value['minutes'] = 0 value['minutes'] = 0
value['formatted_minutes'] = "00" value['formatted_minutes'] = "00"
return values return values
def action_pos_order_paid(self): def action_pos_order_paid(self):
"""Inherited method called when a POS order transitions to 'paid' state.""" """Inherited method called when a POS order transitions to 'paid' state."""
res = super().action_pos_order_paid() res = super().action_pos_order_paid()
kitchen_screen = self.env["kitchen.screen"].search( kitchen_screen = self.env["kitchen.screen"].search(
[("pos_config_id", "=", self.config_id.id)], limit=1 [("pos_config_id", "=", self.config_id.id)], limit=1
) )
@ -251,16 +203,13 @@ class PosOrder(models.Model):
order_line.product_id.pos_categ_ids): order_line.product_id.pos_categ_ids):
order_line.write({'is_cooking': True}) order_line.write({'is_cooking': True})
has_kitchen_items = True has_kitchen_items = True
if has_kitchen_items: if has_kitchen_items:
vals.update({ vals.update({
'is_cooking': True, 'is_cooking': True,
'order_ref': self.name, 'order_ref': self.name,
# Only set order_status to 'draft' if it’s not already set 'order_status': 'ready'
'order_status': self.order_status or 'draft'
}) })
self.write(vals) self.write(vals)
message = { message = {
'res_model': self._name, 'res_model': self._name,
'message': 'pos_order_created', 'message': 'pos_order_created',
@ -269,7 +218,6 @@ class PosOrder(models.Model):
} }
channel = f'pos_order_created_{self.config_id.id}' channel = f'pos_order_created_{self.config_id.id}'
self.env["bus.bus"]._sendone(channel, "notification", message) self.env["bus.bus"]._sendone(channel, "notification", message)
return res return res
@api.onchange("order_status") @api.onchange("order_status")
@ -303,7 +251,6 @@ class PosOrder(models.Model):
self.order_status = "cancel" self.order_status = "cancel"
for line in self.lines: for line in self.lines:
line.order_status = "cancel" line.order_status = "cancel"
message = { message = {
'res_model': self._name, 'res_model': self._name,
'message': 'pos_order_cancelled', 'message': 'pos_order_cancelled',
@ -324,7 +271,6 @@ class PosOrder(models.Model):
if line.product_id.pos_categ_ids and any( if line.product_id.pos_categ_ids and any(
cat.id in kitchen_screen.pos_categ_ids.ids for cat in line.product_id.pos_categ_ids): cat.id in kitchen_screen.pos_categ_ids.ids for cat in line.product_id.pos_categ_ids):
line.order_status = "ready" line.order_status = "ready"
message = { message = {
'res_model': self._name, 'res_model': self._name,
'message': 'pos_order_completed', 'message': 'pos_order_completed',
@ -341,13 +287,10 @@ class PosOrder(models.Model):
[('pos_reference', '=', str(order_name))], limit=1) [('pos_reference', '=', str(order_name))], limit=1)
if not pos_order: if not pos_order:
return False return False
kitchen_screen = self.env['kitchen.screen'].sudo().search( kitchen_screen = self.env['kitchen.screen'].sudo().search(
[("pos_config_id", "=", pos_order.config_id.id)], limit=1) [("pos_config_id", "=", pos_order.config_id.id)], limit=1)
if not kitchen_screen: if not kitchen_screen:
return False return False
unhandled_categories = [] unhandled_categories = []
for line in pos_order.lines: for line in pos_order.lines:
if line.product_id.pos_categ_ids and not any( if line.product_id.pos_categ_ids and not any(
@ -356,119 +299,122 @@ class PosOrder(models.Model):
[c.name for c in line.product_id.pos_categ_ids if c.id not in kitchen_screen.pos_categ_ids.ids]) [c.name for c in line.product_id.pos_categ_ids if c.id not in kitchen_screen.pos_categ_ids.ids])
if unhandled_categories: if unhandled_categories:
return {'category': ", ".join(list(set(unhandled_categories)))} return {'category': ", ".join(list(set(unhandled_categories)))}
if pos_order.order_status not in ['ready', 'cancel']: if pos_order.order_status not in ['ready', 'cancel']:
return True return True
else: else:
return False return False
@api.model @api.model
def create_or_update_kitchen_order(self, orders_data): def process_order_for_kitchen(self, order_data):
"""Create new kitchen order or update existing one with new items.""" """Process already created POS order for kitchen screen display."""
for order_data in orders_data:
pos_reference = order_data.get('pos_reference') pos_reference = order_data.get('pos_reference')
existing_order = self.search( config_id = order_data.get('config_id')
[('pos_reference', '=', pos_reference)], limit=1) pos_order = self.search([
('name', '=', f"Order {pos_reference}"),
('config_id', '=', config_id)
], limit=1)
if not pos_order:
return False
kitchen_screen = self.env["kitchen.screen"].search([ kitchen_screen = self.env["kitchen.screen"].search([
("pos_config_id", "=", order_data.get('config_id')) ("pos_config_id", "=", config_id)
], limit=1) ], limit=1)
if not kitchen_screen: if not kitchen_screen:
continue return False
kitchen_lines = []
if existing_order: for line in pos_order.lines:
if existing_order.order_status in ['ready', 'cancel']: product = line.product_id
continue if product.pos_categ_ids and any(
current_status = existing_order.order_status or 'draft'
existing_line_products = {line.product_id.id: line for line in existing_order.lines}
for line_data in order_data.get('lines', []):
line_vals = line_data[2]
product_id = line_vals.get('product_id')
qty = line_vals.get('qty', 1)
product = self.env['product.product'].browse(product_id)
if not (product.pos_categ_ids and any(
cat.id in kitchen_screen.pos_categ_ids.ids cat.id in kitchen_screen.pos_categ_ids.ids
for cat in product.pos_categ_ids for cat in product.pos_categ_ids):
)): kitchen_lines.append(line)
continue if not kitchen_lines:
return False
if product_id in existing_line_products: for line in kitchen_lines:
existing_line = existing_line_products[product_id] line.write({
if existing_line.qty != qty:
existing_line.write({'qty': qty})
else:
self.env['pos.order.line'].create({
'order_id': existing_order.id,
'product_id': product_id,
'qty': qty,
'price_unit': line_vals.get('price_unit'),
'price_subtotal': line_vals.get('price_subtotal'),
'price_subtotal_incl': line_vals.get('price_subtotal_incl'),
'discount': line_vals.get('discount', 0),
'full_product_name': line_vals.get('full_product_name'),
'is_cooking': True, 'is_cooking': True,
'order_status': current_status, 'order_status': 'draft'
'note': line_vals.get('note', ''),
}) })
pos_order.write({
existing_order.write({ 'is_cooking': True,
'amount_total': order_data.get('amount_total'), 'order_status': 'draft'
'amount_tax': order_data.get('amount_tax'),
}) })
message = {
'res_model': 'pos.order',
'message': 'pos_order_updated',
'config_id': config_id,
'order_id': pos_order.id,
'pos_reference': pos_reference
}
channel = f'pos_order_created_{config_id}'
self.env["bus.bus"]._sendone(channel, "notification", message)
return True
else: @api.model
kitchen_lines = [] def get_kitchen_orders(self, config_id):
for line_data in order_data.get('lines', []): """Get all orders that have kitchen items for the kitchen screen."""
line_vals = line_data[2] kitchen_screen = self.env["kitchen.screen"].search([
product_id = line_vals.get('product_id') ("pos_config_id", "=", config_id)
], limit=1)
product = self.env['product.product'].browse(product_id) if not kitchen_screen:
if product.pos_categ_ids and any( return []
kitchen_orders = self.search([
('config_id', '=', config_id),
('is_cooking', '=', True),
('order_status', 'not in', ['ready', 'cancel'])
])
orders_data = []
for order in kitchen_orders:
# Get only kitchen lines
kitchen_lines = order.lines.filtered(lambda l:
l.product_id.pos_categ_ids and any(
cat.id in kitchen_screen.pos_categ_ids.ids cat.id in kitchen_screen.pos_categ_ids.ids
for cat in product.pos_categ_ids for cat in
): l.product_id.pos_categ_ids
kitchen_lines.append([0, 0, { )
'product_id': product_id, )
'qty': line_vals.get('qty', 1),
'price_unit': line_vals.get('price_unit'),
'price_subtotal': line_vals.get('price_subtotal'),
'price_subtotal_incl': line_vals.get('price_subtotal_incl'),
'discount': line_vals.get('discount', 0),
'full_product_name': line_vals.get('full_product_name'),
'is_cooking': True,
'order_status': order_data.get('order_status', 'draft'),
'note': line_vals.get('note', ''),
}])
if kitchen_lines: if kitchen_lines:
self.create({ line_data = []
'pos_reference': pos_reference, for line in kitchen_lines:
'session_id': order_data.get('session_id'), line_data.append({
'amount_total': order_data.get('amount_total'), 'id': line.id,
'amount_paid': order_data.get('amount_paid', 0), 'product_id': line.product_id.id,
'amount_return': order_data.get('amount_return', 0), 'product_name': line.product_id.name,
'amount_tax': order_data.get('amount_tax'), 'qty': line.qty,
'lines': kitchen_lines, 'note': line.note or '',
'is_cooking': True, 'order_status': line.order_status or 'draft'
'order_status': order_data.get('order_status', 'draft'), })
'company_id': order_data.get('company_id'), orders_data.append({
'table_id': order_data.get('table_id'), 'id': order.id,
'config_id': order_data.get('config_id'), 'pos_reference': order.pos_reference,
'state': 'draft', 'name': order.name,
'name': self.env['ir.sequence'].next_by_code('pos.order') or '/', 'table_id': order.table_id.id if order.table_id else False,
'table_name': order.table_id.name if order.table_id else '',
'order_status': order.order_status,
'lines': line_data,
'date_order': order.date_order,
'amount_total': order.amount_total
}) })
return orders_data
@api.model
def update_kitchen_order_status(self, order_id, status):
"""Update kitchen order status."""
order = self.browse(order_id)
if order.exists():
order.write({'order_status': status})
kitchen_lines = order.lines.filtered(lambda l: l.is_cooking)
kitchen_lines.write({'order_status': status})
message = { message = {
'res_model': 'pos.order', 'res_model': 'pos.order',
'message': 'pos_order_updated', 'message': 'kitchen_order_status_updated',
'config_id': order_data.get('config_id') 'config_id': order.config_id.id,
'order_id': order.id,
'status': status
} }
channel = f'pos_order_created_{order_data.get("config_id")}' channel = f'pos_order_created_{order.config_id.id}'
self.env["bus.bus"]._sendone(channel, "notification", message) self.env["bus.bus"]._sendone(channel, "notification", message)
return True return True
return False
@api.model @api.model
def check_order_status(self, dummy_param, order_reference): def check_order_status(self, dummy_param, order_reference):
@ -476,7 +422,6 @@ class PosOrder(models.Model):
pos_order = self.env['pos.order'].sudo().search([ pos_order = self.env['pos.order'].sudo().search([
('pos_reference', '=', str(order_reference)) ('pos_reference', '=', str(order_reference))
], limit=1) ], limit=1)
if not pos_order: if not pos_order:
return True return True
return pos_order.order_status in ['draft', 'waiting'] return pos_order.order_status in ['draft', 'waiting']

BIN
pos_kitchen_screen_odoo/static/description/assets/screenshots/pos12.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

BIN
pos_kitchen_screen_odoo/static/description/assets/screenshots/pos13.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

BIN
pos_kitchen_screen_odoo/static/description/assets/screenshots/pos14.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

90
pos_kitchen_screen_odoo/static/description/index.html

@ -832,6 +832,96 @@
</div> </div>
</div> </div>
</div> </div>
<div class="position-relative mb-4"
style="border-radius:10px; background-color:#f4f4f4">
<div class="p-md-5 p-3 position-relative">
<div class="row">
<div class="col-md-12">
<h1 style="font-weight:bold; font-size:calc(1.1rem + 1vw); line-height:120%; text-align:center; text-transform:capitalize; font-size: 40px;
font-weight: 700;">
<!-- <span style="color:#121212; font-size:calc(1.1rem + 1vw)">Store Backup to-->
<!---->
<!-- </span>-->
<!-- <span style="color: var(&#45;&#45;primary-color); font-size:calc(1.1rem + 1vw)">AmazonS3.</span>-->
</h1>
</div>
<div class="col-md-12 mb-4">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:var(--text-color-light)">
Adding preparation time to the product variant</p>
</div>
<div class="col-md-12 text-center">
<div class="d-inline-block p-3 shadow-sm"
style="background-color:#fff; border-radius:10px">
<img alt="" class="img-fluid"
loading="lazy"
src="./assets/screenshots/pos12.png"
style="min-height: 1px;">
</div>
</div>
</div>
</div>
</div>
<div class="position-relative mb-4"
style="border-radius:10px; background-color:#f4f4f4">
<div class="p-md-5 p-3 position-relative">
<div class="row">
<div class="col-md-12">
<h1 style="font-weight:bold; font-size:calc(1.1rem + 1vw); line-height:120%; text-align:center; text-transform:capitalize; font-size: 40px;
font-weight: 700;">
<!-- <span style="color:#121212; font-size:calc(1.1rem + 1vw)">Store Backup to-->
<!---->
<!-- </span>-->
<!-- <span style="color: var(&#45;&#45;primary-color); font-size:calc(1.1rem + 1vw)">AmazonS3.</span>-->
</h1>
</div>
<div class="col-md-12 mb-4">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:var(--text-color-light)">
Enable the Change Stage field to update the cooking stage automatically once the preparation time is completed.</p>
</div>
<div class="col-md-12 text-center">
<div class="d-inline-block p-3 shadow-sm"
style="background-color:#fff; border-radius:10px">
<img alt="" class="img-fluid"
loading="lazy"
src="./assets/screenshots/pos13.png"
style="min-height: 1px;">
</div>
</div>
</div>
</div>
</div>
<div class="position-relative mb-4"
style="border-radius:10px; background-color:#f4f4f4">
<div class="p-md-5 p-3 position-relative">
<div class="row">
<div class="col-md-12">
<h1 style="font-weight:bold; font-size:calc(1.1rem + 1vw); line-height:120%; text-align:center; text-transform:capitalize; font-size: 40px;
font-weight: 700;">
<!-- <span style="color:#121212; font-size:calc(1.1rem + 1vw)">Store Backup to-->
<!---->
<!-- </span>-->
<!-- <span style="color: var(&#45;&#45;primary-color); font-size:calc(1.1rem + 1vw)">AmazonS3.</span>-->
</h1>
</div>
<div class="col-md-12 mb-4">
<p style="font-weight:400; font-size:16px; line-height:150%; text-align:center; color:var(--text-color-light)">
In the kitchen screen, after adding a product with preparation time,
it will be displayed under the Cooking stage. Once accepted,
it moves to the Ready stage and the countdown starts.
After the countdown is completed, it automatically moves to the Completed stage.</p>
</div>
<div class="col-md-12 text-center">
<div class="d-inline-block p-3 shadow-sm"
style="background-color:#fff; border-radius:10px">
<img alt="" class="img-fluid"
loading="lazy"
src="./assets/screenshots/pos14.png"
style="min-height: 1px;">
</div>
</div>
</div>
</div>
</div>
</div> </div>
<div aria-labelledby="feature-tab" <div aria-labelledby="feature-tab"
class="tab-pane fade show py-1" id="feature" class="tab-pane fade show py-1" id="feature"

5
pos_kitchen_screen_odoo/static/src/js/fields_load.js

@ -15,6 +15,11 @@ patch(PosStore.prototype, {
this.pos_orders = loadedData['pos.order']; this.pos_orders = loadedData['pos.order'];
this.pos_order_lines = loadedData['pos.order.line']; this.pos_order_lines = loadedData['pos.order.line'];
}, },
createNewOrder() {
const order = super.createNewOrder(...arguments);
return order
}
}); });

94
pos_kitchen_screen_odoo/static/src/js/order_button.js

@ -6,25 +6,26 @@ import { AlertDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
import { _t } from "@web/core/l10n/translation"; import { _t } from "@web/core/l10n/translation";
import { TicketScreen } from "@point_of_sale/app/screens/ticket_screen/ticket_screen"; import { TicketScreen } from "@point_of_sale/app/screens/ticket_screen/ticket_screen";
/** /**
* @props partner * @props partner
*/ */
patch(ActionpadWidget.prototype, { patch(ActionpadWidget.prototype, {
setup() { setup() {
super.setup(); super.setup();
this.orm = useService("orm"); this.orm = useService("orm");
console.log("ActionpadWidget")
}, },
get swapButton() { get swapButton() {
return ( return (
this.pos.config.module_pos_restaurant && this.pos.mainScreen.component !== TicketScreen this.pos.config.module_pos_restaurant && this.pos.mainScreen.component !== TicketScreen
); );
}, },
get currentOrder() { get currentOrder() {
return this.pos.get_order(); return this.pos.get_order();
}, },
get swapButtonClasses() { get swapButtonClasses() {
return { return {
"highlight btn-primary justify-content-between": this.displayCategoryCount.length, "highlight btn-primary justify-content-between": this.displayCategoryCount.length,
@ -32,11 +33,11 @@ setup() {
altlight: !this.hasChangesToPrint && this.currentOrder?.hasSkippedChanges(), altlight: !this.hasChangesToPrint && this.currentOrder?.hasSkippedChanges(),
}; };
}, },
async submitOrder() { async submitOrder() {
var line = []
var self = this; var self = this;
if (!this.clicked) { if (!this.uiState.clicked) {
this.clicked = true; this.uiState.clicked = true;
try { try {
await self.orm.call("pos.order", "check_order_status", ["", this.pos.get_order().pos_reference]).then(function(result){ await self.orm.call("pos.order", "check_order_status", ["", this.pos.get_order().pos_reference]).then(function(result){
if (result == false){ if (result == false){
@ -50,60 +51,29 @@ setup() {
self.kitchen_order_status = true self.kitchen_order_status = true
} }
}); });
if (self.kitchen_order_status){ if (self.kitchen_order_status){
await this.pos.sendOrderInPreparationUpdateLastChange(this.currentOrder); await this.pos.sendOrderInPreparationUpdateLastChange(this.currentOrder);
await this.processOrderForKitchen();
for (const orders of this.pos.get_order().lines) {
let actualQty = orders.qty || orders.quantity || orders.get_quantity() || 1;
line.push([0, 0, {
'qty': actualQty,
'price_unit': orders.price_unit,
'price_subtotal': orders.price_subtotal,
'price_subtotal_incl': orders.price_subtotal_incl,
'discount': orders.discount,
'product_id': orders.product_id.id,
'tax_ids': [
[6, 0, orders.tax_ids.map((tax) => tax.id)]
],
'id': orders.id,
'pack_lot_ids': [],
'full_product_name': orders.product_id.display_name,
'price_extra': orders.price_extra,
'name': orders.product_id.display_name,
'is_cooking': true,
'note': orders.note
}])
}
const date = new Date(self.currentOrder.date_order.replace(' ', 'T'));
var orders = [{
'pos_reference': this.pos.get_order().pos_reference,
'session_id': this.pos.get_order().session_id.id,
'amount_total': this.pos.get_order().amount_total,
'amount_paid': this.pos.get_order().amount_paid,
'amount_return': this.pos.get_order().amount_return,
'amount_tax': this.pos.get_order().amount_tax,
'lines': line,
'is_cooking': true,
'order_status': 'draft',
'company_id': this.pos.company.id,
'hour': date.getHours(),
'minutes': date.getMinutes(),
'table_id': this.pos.get_order().table_id.id,
'floor': this.pos.get_order().table_id.floor_id.name,
'config_id': this.pos.get_order().config_id.id
}]
await self.orm.call("pos.order", "create_or_update_kitchen_order", [orders]);
this.env.bus.trigger('pos-kitchen-screen-update'); this.env.bus.trigger('pos-kitchen-screen-update');
} }
} finally { } finally {
this.clicked = false; this.uiState.clicked = false;
} }
} }
}, },
async processOrderForKitchen() {
var self = this;
const orderData = {
'pos_reference': this.pos.get_order().pos_reference,
'config_id': this.pos.get_order().config_id.id,
'table_id': this.pos.get_order().table_id.id,
'session_id': this.pos.get_order().session_id.id
};
this.pos.syncAllOrders()
await self.orm.call("pos.order", "process_order_for_kitchen", [orderData]);
},
hasQuantity(order) { hasQuantity(order) {
if (!order) { if (!order) {
return false; return false;
@ -113,6 +83,7 @@ setup() {
); );
} }
}, },
get highlightPay() { get highlightPay() {
return ( return (
this.currentOrder?.lines?.length && this.currentOrder?.lines?.length &&
@ -120,14 +91,22 @@ setup() {
this.hasQuantity(this.currentOrder) this.hasQuantity(this.currentOrder)
); );
}, },
get hasChangesToPrint() {
let hasChange = this.pos.getOrderChanges();
hasChange =
hasChange.generalNote == ""
? true // for the case when removed all general note
: hasChange.count || hasChange.generalNote || hasChange.modeUpdate;
return hasChange;
},
get categoryCount() { get categoryCount() {
const orderChanges = this.getOrderChanges(); const orderChanges = this.getOrderChanges();
const linesChanges = orderChanges.orderlines; const linesChanges = orderChanges.orderlines;
const categories = Object.values(linesChanges).reduce((acc, curr) => { const categories = Object.values(linesChanges).reduce((acc, curr) => {
const categories = const categories =
this.models["product.product"].get(curr.product_id)?.pos_categ_ids || []; this.models["product.product"].get(curr.product_id)?.pos_categ_ids || [];
for (const category of categories.slice(0, 1)) { for (const category of categories.slice(0, 1)) {
if (!acc[category.id]) { if (!acc[category.id]) {
acc[category.id] = { acc[category.id] = {
@ -138,18 +117,18 @@ setup() {
acc[category.id].count += curr.quantity; acc[category.id].count += curr.quantity;
} }
} }
return acc; return acc;
}, {}); }, {});
return [ return [
...Object.values(categories), ...Object.values(categories),
...("generalNote" in orderChanges ? [{ count: 1, name: _t("General Note") }] : []), ...("generalNote" in orderChanges ? [{ count: 1, name: _t("General Note") }] : []),
]; ];
}, },
get displayCategoryCount() { get displayCategoryCount() {
return this.pos.categoryCount.slice(0, 4); return this.pos.categoryCount.slice(0, 4);
}, },
get isCategoryCountOverflow() { get isCategoryCountOverflow() {
if (this.pos.categoryCount.length > 4) { if (this.pos.categoryCount.length > 4) {
return true; return true;
@ -157,3 +136,4 @@ setup() {
return false; return false;
}, },
}); });

1
pos_kitchen_screen_odoo/static/src/js/order_pay.js

@ -20,6 +20,7 @@ import {
patch(PosStore.prototype, { patch(PosStore.prototype, {
async setup(env) { async setup(env) {
await super.setup(...arguments); await super.setup(...arguments);
console.log("PosStore",PosStore)
this.kitchen = true; this.kitchen = true;

Loading…
Cancel
Save