Skip to content
Closed
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
46 changes: 46 additions & 0 deletions pos_next/events/invoice.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2024, POS Next and contributors
# For license information, please see license.txt

"""
Real-time event handlers for invoice creation.
"""

import frappe
from frappe import _

def emit_invoice_created_event(doc, method=None):
"""
Emit real-time event when invoice is created.

This can be used to notify other terminals about new sales,
update dashboards, or trigger other real-time UI updates.

Args:
doc: Sales Invoice document
method: Hook method name
"""
if not doc.is_pos:
return

try:
event_data = {
"invoice_name": doc.name,
"grand_total": doc.grand_total,
"customer": doc.customer,
"pos_profile": doc.pos_profile,
"timestamp": frappe.utils.now(),
}

frappe.publish_realtime(
event="pos_invoice_created",
message=event_data,
user=None,
after_commit=True
)

except Exception as e:
frappe.log_error(
title=_("Real-time Invoice Created Event Error"),
message=f"Failed to emit invoice created event for {doc.name}: {str(e)}"
)
57 changes: 57 additions & 0 deletions pos_next/events/pos_profile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2024, POS Next and contributors
# For license information, please see license.txt

"""
Real-time event handlers for POS profile updates.
"""

import frappe
from frappe import _

def emit_pos_profile_updated_event(doc, method=None):
"""
Emit real-time event when POS Profile is updated.

This event notifies all connected POS terminals about configuration changes,
particularly item group filters, allowing them to clear their cache and reload
items automatically without manual intervention.

Args:
doc: POS Profile document
method: Hook method name (on_update, validate, etc.)
"""
try:
# Check if item_groups have changed by comparing with the original doc
if doc.has_value_changed("item_groups"):
# Extract current item groups
current_item_groups = [{"item_group": ig.item_group} for ig in doc.get("item_groups", [])]

# Prepare event data
event_data = {
"pos_profile": doc.name,
"item_groups": current_item_groups,
"timestamp": frappe.utils.now(),
"change_type": "item_groups_updated"
}

# Emit event to all connected clients
# Event name: pos_profile_updated
# Clients can subscribe to this event and invalidate their cache
frappe.publish_realtime(
event="pos_profile_updated",
message=event_data,
user=None, # Broadcast to all users
after_commit=True # Only emit after successful DB commit
)

frappe.logger().info(
f"Emitted pos_profile_updated event for {doc.name} - item groups changed"
)

except Exception as e:
# Log error but don't fail the transaction
frappe.log_error(
title=_("Real-time POS Profile Update Event Error"),
message=f"Failed to emit POS profile update event for {doc.name}: {str(e)}"
)
89 changes: 1 addition & 88 deletions pos_next/realtime_events.py → pos_next/events/stock.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@
# For license information, please see license.txt

"""
Real-time event handlers for POS Next.
Emits Socket.IO events when stock-affecting transactions occur.
Real-time event handlers for stock updates.
"""

import frappe
from frappe import _

from pos_next.api.items import get_stock_quantities


def emit_stock_update_event(doc, method=None):
"""
Emit real-time stock update event when Sales Invoice is submitted.
Expand Down Expand Up @@ -98,88 +96,3 @@ def emit_stock_update_event(doc, method=None):
title=_("Real-time Stock Update Event Error"),
message=f"Failed to emit stock update event for {doc.name}: {str(e)}"
)


def emit_invoice_created_event(doc, method=None):
"""
Emit real-time event when invoice is created.

This can be used to notify other terminals about new sales,
update dashboards, or trigger other real-time UI updates.

Args:
doc: Sales Invoice document
method: Hook method name
"""
if not doc.is_pos:
return

try:
event_data = {
"invoice_name": doc.name,
"grand_total": doc.grand_total,
"customer": doc.customer,
"pos_profile": doc.pos_profile,
"timestamp": frappe.utils.now(),
}

frappe.publish_realtime(
event="pos_invoice_created",
message=event_data,
user=None,
after_commit=True
)

except Exception as e:
frappe.log_error(
title=_("Real-time Invoice Created Event Error"),
message=f"Failed to emit invoice created event for {doc.name}: {str(e)}"
)


def emit_pos_profile_updated_event(doc, method=None):
"""
Emit real-time event when POS Profile is updated.

This event notifies all connected POS terminals about configuration changes,
particularly item group filters, allowing them to clear their cache and reload
items automatically without manual intervention.

Args:
doc: POS Profile document
method: Hook method name (on_update, validate, etc.)
"""
try:
# Check if item_groups have changed by comparing with the original doc
if doc.has_value_changed("item_groups"):
# Extract current item groups
current_item_groups = [{"item_group": ig.item_group} for ig in doc.get("item_groups", [])]

# Prepare event data
event_data = {
"pos_profile": doc.name,
"item_groups": current_item_groups,
"timestamp": frappe.utils.now(),
"change_type": "item_groups_updated"
}

# Emit event to all connected clients
# Event name: pos_profile_updated
# Clients can subscribe to this event and invalidate their cache
frappe.publish_realtime(
event="pos_profile_updated",
message=event_data,
user=None, # Broadcast to all users
after_commit=True # Only emit after successful DB commit
)

frappe.logger().info(
f"Emitted pos_profile_updated event for {doc.name} - item groups changed"
)

except Exception as e:
# Log error but don't fail the transaction
frappe.log_error(
title=_("Real-time POS Profile Update Event Error"),
message=f"Failed to emit POS profile update event for {doc.name}: {str(e)}"
)
28 changes: 14 additions & 14 deletions pos_next/hooks.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pos_next.utils import get_build_version
from pos_next.utils.version import get_build_version

app_name = "pos_next"
app_title = "POS Next"
Expand Down Expand Up @@ -121,15 +121,15 @@
# Installation
# ------------

# before_install = "pos_next.install.before_install"
after_install = "pos_next.install.after_install"
after_migrate = "pos_next.install.after_migrate"
# before_install = "pos_next.utils.install.before_install"
after_install = "pos_next.utils.install.after_install"
after_migrate = "pos_next.utils.install.after_migrate"

# Uninstallation
# ------------

before_uninstall = "pos_next.uninstall.before_uninstall"
# after_uninstall = "pos_next.uninstall.after_uninstall"
before_uninstall = "pos_next.utils.uninstall.before_uninstall"
# after_uninstall = "pos_next.utils.uninstall.after_uninstall"

# Integration Setup
# ------------------
Expand Down Expand Up @@ -169,7 +169,7 @@
# ----------------
# Custom query for company-aware item filtering
standard_queries = {
"Item": "pos_next.validations.item_query"
"Item": "pos_next.utils.validations.item_query"
}

# DocType Class
Expand All @@ -186,17 +186,17 @@

doc_events = {
"Item": {
"validate": "pos_next.validations.validate_item"
"validate": "pos_next.utils.validations.validate_item"
},
"Sales Invoice": {
"validate": "pos_next.api.sales_invoice_hooks.validate",
"before_cancel": "pos_next.api.sales_invoice_hooks.before_cancel",
"on_submit": "pos_next.realtime_events.emit_stock_update_event",
"on_cancel": "pos_next.realtime_events.emit_stock_update_event",
"after_insert": "pos_next.realtime_events.emit_invoice_created_event"
"on_submit": "pos_next.events.stock.emit_stock_update_event",
"on_cancel": "pos_next.events.stock.emit_stock_update_event",
"after_insert": "pos_next.events.invoice.emit_invoice_created_event"
},
"POS Profile": {
"on_update": "pos_next.realtime_events.emit_pos_profile_updated_event"
"on_update": "pos_next.events.pos_profile.emit_pos_profile_updated_event"
}
}

Expand All @@ -219,7 +219,7 @@
# Testing
# -------

# before_tests = "pos_next.install.before_tests"
# before_tests = "pos_next.utils.install.before_tests"

# Overriding Methods
# ------------------------------
Expand Down Expand Up @@ -293,4 +293,4 @@
# }


website_route_rules = [{'from_route': '/pos/<path:app_path>', 'to_route': 'pos'},]
website_route_rules = [{'from_route': '/pos/<path:app_path>', 'to_route': 'pos'},]
1 change: 1 addition & 0 deletions pos_next/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .version import get_build_version, get_app_version
File renamed without changes.
File renamed without changes.
File renamed without changes.
3 changes: 2 additions & 1 deletion pos_next/utils.py → pos_next/utils/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

from pos_next import __version__ as app_version

_BASE_DIR = Path(__file__).resolve().parent
# _BASE_DIR should point to the pos_next app directory
_BASE_DIR = Path(__file__).resolve().parent.parent
_VERSION_FILE = _BASE_DIR / "public" / "pos" / "version.json"
_MANIFEST_FILE = _BASE_DIR / "public" / "pos" / "manifest.webmanifest"
_FALLBACK_VERSION: str | None = None
Expand Down
Loading