From 7f8a627a8c1db52ecd29350519a817442243d2c7 Mon Sep 17 00:00:00 2001 From: Bhagya-K Date: Mon, 22 Jun 2026 15:02:55 +0530 Subject: [PATCH] DEV: Probation Tracking --- .../firebase_integration/__init__.py | 2 + .../firebase_integration/__manifest__.py | 21 +++ ...to-firebase-adminsdk-fbsvc-60336fd855.json | 13 ++ .../models/discuss_channel_notify.py | 155 ++++++++++++++++++ .../static/description/banner.png | Bin 0 -> 17996 bytes .../static/description/icon.png | Bin 0 -> 55818 bytes .../static/description/index.html | 21 +++ .../firebase_integration/tools/__init__.py | 2 + .../firebase_integration/tools/firebase.py | 109 ++++++++++++ 9 files changed, 323 insertions(+) create mode 100644 addons_extensions/firebase_integration/__init__.py create mode 100644 addons_extensions/firebase_integration/__manifest__.py create mode 100644 addons_extensions/firebase_integration/hrmsopzento-firebase-adminsdk-fbsvc-60336fd855.json create mode 100644 addons_extensions/firebase_integration/models/discuss_channel_notify.py create mode 100644 addons_extensions/firebase_integration/static/description/banner.png create mode 100644 addons_extensions/firebase_integration/static/description/icon.png create mode 100644 addons_extensions/firebase_integration/static/description/index.html create mode 100644 addons_extensions/firebase_integration/tools/__init__.py create mode 100644 addons_extensions/firebase_integration/tools/firebase.py diff --git a/addons_extensions/firebase_integration/__init__.py b/addons_extensions/firebase_integration/__init__.py new file mode 100644 index 000000000..e47d26c5d --- /dev/null +++ b/addons_extensions/firebase_integration/__init__.py @@ -0,0 +1,2 @@ +from . import tools +from . import models diff --git a/addons_extensions/firebase_integration/__manifest__.py b/addons_extensions/firebase_integration/__manifest__.py new file mode 100644 index 000000000..1e81d8681 --- /dev/null +++ b/addons_extensions/firebase_integration/__manifest__.py @@ -0,0 +1,21 @@ +{ + "name": "Firebase Integration", + "version": "18.0.1.0.0", + "category": "Tools", + "author": "IdeaCode Academy", + "license": "LGPL-3", + "summary": "Integrate Firebase services and push notifications with Odoo", + "depends": ["base", "bus","mail"], + "external_dependencies": { + "python": ["firebase-admin"], + }, + "data": [ + "views/res_users.xml", + ], + "images": ["static/description/banner.png"], + "installable": True, + "application": False, + "auto_install": False, + "price": 0.0, + "currency": "USD", +} diff --git a/addons_extensions/firebase_integration/hrmsopzento-firebase-adminsdk-fbsvc-60336fd855.json b/addons_extensions/firebase_integration/hrmsopzento-firebase-adminsdk-fbsvc-60336fd855.json new file mode 100644 index 000000000..033490c8c --- /dev/null +++ b/addons_extensions/firebase_integration/hrmsopzento-firebase-adminsdk-fbsvc-60336fd855.json @@ -0,0 +1,13 @@ +{ + "type": "service_account", + "project_id": "hrmsopzento", + "private_key_id": "60336fd85549183b6c890121aaa3f08256d3f0a4", + "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDZn3agMptdcJ7n\noZIS1E0x/3PBB0uPVljoQRrqDwwEPtwKC+Sh9DY/eiXbvXyQGfzH3LkToVgvNPCY\nsFRfPnGtp9W45bwYOi0qXc8MWzYiBLRfO663hOjh90AfTEgE02wD3DOWo9eFlzMn\nJMPrOZUD0fNpzQFXQ7o8ufdrCS40d4hDQNiMGSx2hPPOnmJioz2GOr1ABhxNFJQY\nv53L1PEP1kCEnoQcCKfpuMPNY2ApzlIEndLoBhr1W5RsHp9web22CukqtJYzVCbw\naWJymZQFSkos5rmCSCvkaTvtEYBkl//4t++WjbNSxL8C48EH1O97Hg4djYULnL1D\n/GmSIYibAgMBAAECggEAVHkYk+Bw/Fk95U2LJPHxsQmmhfPt+Yqb4jN7XgVPNcqs\noN2y9saT1Bn23g/0bP8ZZv8ffCYx08kp5yry5TGY8L5oMGhElebnJz3Yo8Q4BAZt\neVXyYNwfha7y3fM/NVhX4ju0brHUc8+YFIap4gGs/Rme8Z+Y+KWagf3xs0OSAtz3\n0d6rOsMl7UfJojChrx70CrwB0y+O+3vbD+IzInWq0RBjcu78VqCiUP+X6BuKmSgN\n2qp61FrW6eNgY1M6thL2UZeDke5hEfLcjWcdSskTj7/yONErzgFiT754IiWXMGPd\n0gGKBAJKkmmBy1stGR/5JoaqV8fVt8GFypm1LZcJEQKBgQD1EEJgyV6IyPWGzu8m\nYhW80zSQ0fQxPX9Y62UP52TecUY5qMvMOmBdec8LE18IKIRgBesCvtdtv2am0rLs\nXg/1Yrfm7AsR/eEYRY3E/8Oyk+XVteUxGR6ZgAIUSLXAsnsfx3/5CkqVTszASime\nvK2httSvmHwWaWvALnAFv3oncwKBgQDjVbUa/jBxf4N2Hcf4oYTJSfkTWa2Llwvm\n63yjcPaqm6HS1psgPd4ZiITEg4UOYpL8Cngb5hqRRIusZGatdBxkUi3AunDuOORL\nYGcn2Zka3aXtTqXzXyhXR3aQH3m2wn7KGDUs4lcoUC/x30UQKqNpWvIpfelLdNgA\n5ZyniSZAOQKBgQDu0Kt/Gn3Pmtb6SorvwsIgQ0qEnrXzjlSd2Leh6gN4arbe1cnU\n+kaSkXPc/UGs958Y3GuLP2M9BjsI82d9xKSUo2FH3ltjax+CwbVId17EljByNVJm\nqG4TdJWSItFMOiKWc5oYnZjVK/eIpD0u/fvPDhbyEA1M4espW5e7Yj+uVQKBgC2g\n7ELItixxrY8tlw9+S8qjAE0z+LNF0+u7ZD7h04CW0DojPOuRv1xcnFldFH24p0vT\nRhxDaR2zJl2poTo7Td+M5wYB5dzKqne+l7XV5PcRedZRrNlWRiCOhWuUBbf6/bvO\ndA3YOCotPhJL/+6owDfLO0O8s/CjOR+k9nZh/r1xAoGAbJJoQhBrF8sCHuTi9Hev\nRrwKnL8Ck5HPB19SkifWA9lg604w2LfRJ1ijOKSm9G1ADLT5a6XfsU7tM/6oG5Np\n3tBxhgEpX03+NS3cwRgYGdzVNS+X5D/9uduCiN0Y4cDUjyin1OT+acOOhd0YtdGe\n9Rp7Ae9GrOKPQ5GvRazbmOI=\n-----END PRIVATE KEY-----\n", + "client_email": "firebase-adminsdk-fbsvc@hrmsopzento.iam.gserviceaccount.com", + "client_id": "111625966108394286408", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-fbsvc%40hrmsopzento.iam.gserviceaccount.com", + "universe_domain": "googleapis.com" +} diff --git a/addons_extensions/firebase_integration/models/discuss_channel_notify.py b/addons_extensions/firebase_integration/models/discuss_channel_notify.py new file mode 100644 index 000000000..0f22c6b26 --- /dev/null +++ b/addons_extensions/firebase_integration/models/discuss_channel_notify.py @@ -0,0 +1,155 @@ +from odoo import models +import logging +import re + +_logger = logging.getLogger(__name__) + + +class DiscussChannelFirebaseNotify(models.Model): + _inherit = "discuss.channel" + + def _notify_thread(self, message, msg_vals=False, **kwargs): + """ + Extend Odoo Discuss notifications with Firebase push notifications. + """ + res = super()._notify_thread( + message, + msg_vals=msg_vals, + **kwargs + ) + + try: + recipients = self._notify_get_recipients( + message, + msg_vals or {}, + **kwargs + ) + + _logger.info( + "Firebase notification processing. Channel=%s Message=%s Recipients=%s", + self.display_name, + message.id, + len(recipients), + ) + + notifications = [] + + for recipient in recipients: + user = False + + # Direct user recipient + if recipient.get("uid"): + user = ( + self.env["res.users"] + .sudo() + .browse(recipient["uid"]) + ) + + # Channel member recipient (uid=False) + elif recipient.get("id"): + partner = ( + self.env["res.partner"] + .sudo() + .browse(recipient["id"]) + ) + + user = partner.user_ids[:1] + + if not user: + continue + + token = user.token + + if not token: + _logger.info( + "Skipping user %s: no token", + user.name, + ) + continue + + # Record name + record_name = ( + msg_vals.get("record_name") + if msg_vals and isinstance(msg_vals, dict) + else message.record_name + ) + + # Author + author = message.author_id + + if self.channel_type == "chat": + title = author.name or "New Message" + + elif self.channel_type == "channel": + title = ( + f"#{record_name} - {author.name}" + if record_name + else author.name + ) + + elif self.channel_type == "group": + title = ( + f"{record_name} - {author.name}" + if record_name + else author.name + ) + + else: + title = record_name or author.name or "New Message" + + # Remove html tags + body_html = ( + msg_vals.get("body") + if msg_vals and msg_vals.get("body") + else message.body + ) + + body = re.sub( + r"<[^>]+>", + "", + body_html or "", + ).strip() + + payload = { + "action": "mail.action_discuss", + "channel_id": str(self.id), + "message_id": str(message.id), + } + + if self.channel_type: + payload["channel_type"] = self.channel_type + + notifications.append({ + "token": token, + "title": title, + "body": body, + "data": payload, + }) + + _logger.info( + "Prepared Firebase notification for user=%s", + user.name, + ) + + if notifications: + _logger.info( + "Sending %s Firebase notifications", + len(notifications), + ) + + self.env["firebase.service"].send_notification( + notifications + ) + + else: + _logger.info( + "No Firebase notifications to send" + ) + + except Exception as exc: + _logger.exception( + "Firebase notification error: %s", + exc + ) + + return res \ No newline at end of file diff --git a/addons_extensions/firebase_integration/static/description/banner.png b/addons_extensions/firebase_integration/static/description/banner.png new file mode 100644 index 0000000000000000000000000000000000000000..a7b53e291f610cf0f3e7d9f7245af0486e8cf410 GIT binary patch literal 17996 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 literal 0 HcmV?d00001 diff --git a/addons_extensions/firebase_integration/static/description/icon.png b/addons_extensions/firebase_integration/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..16dd809944c113998efbd5563224efaf7d8e94ce GIT binary patch literal 55818 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⋘30rq#jUD*G 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 z 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 FzW}op(xCtV literal 0 HcmV?d00001 diff --git a/addons_extensions/firebase_integration/static/description/index.html b/addons_extensions/firebase_integration/static/description/index.html new file mode 100644 index 000000000..a175cea46 --- /dev/null +++ b/addons_extensions/firebase_integration/static/description/index.html @@ -0,0 +1,21 @@ +
+
+

Firebase Integration

+ +

Configuration

+

Add the following key to your odoo.conf file:

+
[options]
+firebase_private_key_path = /home/documents/cre.json
+ +

Usage

+

Import and call the function anywhere within your backend Odoo modules:

+
from odoo.addons.firebase_integration.tools.firebase import send_firebase_notifications
+
+msg = [
+    {'token': 'DEVICE_TOKEN_1', 'body': 'Notification Body', 'title': 'Notification Title'},
+    {'token': 'DEVICE_TOKEN_2', 'body': 'Another Body', 'title': 'Another Title'}
+]
+
+success_sent_message_count = send_firebase_notifications(msg)
+
+
diff --git a/addons_extensions/firebase_integration/tools/__init__.py b/addons_extensions/firebase_integration/tools/__init__.py new file mode 100644 index 000000000..40dee207e --- /dev/null +++ b/addons_extensions/firebase_integration/tools/__init__.py @@ -0,0 +1,2 @@ +from . import firebase +from . import firebase_service \ No newline at end of file diff --git a/addons_extensions/firebase_integration/tools/firebase.py b/addons_extensions/firebase_integration/tools/firebase.py new file mode 100644 index 000000000..b4744e924 --- /dev/null +++ b/addons_extensions/firebase_integration/tools/firebase.py @@ -0,0 +1,109 @@ +import logging +import firebase_admin +from firebase_admin import credentials, messaging +from odoo.tools import config + +# Fetch the credential file path safely from odoo.conf +firebase_key_path = config.get("firebase_private_key_path") +_logger = logging.getLogger(__name__) + +# Initialize the app safely to prevent "app already exists" runtime crashes +try: + firebase_app = firebase_admin.get_app() +except ValueError: + if firebase_key_path: + firebase_cred = credentials.Certificate(firebase_key_path) + firebase_app = firebase_admin.initialize_app(firebase_cred) + else: + # Fallback to default application credentials if config key is missing + firebase_app = firebase_admin.initialize_app() + + +def send_firebase_notifications(messages: list) -> int: + """Sends list of notification messages using Firebase Cloud Messaging. + + Expecting input layout: + [ + {'token': '...', 'body': '...', 'title': '...'}, + ] + """ + if not messages: + return 0 + + # Build the payload using native Firebase messaging objects + fcm_messages = [] + for msg in messages: + token = msg.get("token") + if not token: + continue + notification = messaging.Notification( + title=msg.get("title", ""), + body=msg.get("body", ""), + ) + # include optional data payload + data_payload = msg.get("data") + fcm_messages.append( + messaging.Message( + notification=notification, + token=token, + data=data_payload if isinstance(data_payload, dict) else None, + ) + ) + + if not fcm_messages: + return 0 + + # Execute the batch transmission using the Firebase Admin SDK + try: + # The SDK / FCM backend limits batch sizes; be conservative and chunk (500 is a safe upper bound). + success_total = 0 + chunk_size = 500 + + for i in range(0, len(fcm_messages), chunk_size): + batch = fcm_messages[i : i + chunk_size] + + # Try newer API first (send_all), fall back to send_multicast for older SDK versions + if hasattr(messaging, 'send_all'): + response = messaging.send_all(batch) + _logger.info( + "Firebase Success Count: %s", + response.success_count + ) + + _logger.info( + "Firebase Failure Count: %s", + response.failure_count + ) + + for idx, resp in enumerate(response.responses): + if not resp.success: + _logger.error( + "Firebase Error %s: %s", + idx, + resp.exception + ) + else: + # Older firebase-admin SDK: use send_multicast + from firebase_admin.messaging import MulticastMessage + multicast = MulticastMessage(tokens=[m.token for m in batch if m.token]) + # send_multicast doesn't support per-token custom payloads; use individual sends as fallback + success_count = 0 + for msg in batch: + try: + messaging.send(msg) + success_count += 1 + except Exception as e: + _logger.debug("Failed to send message to token %s: %s", msg.token, e) + response = type('obj', (object,), {'success_count': success_count})() + + sent = getattr(response, "success_count", 0) + success_total += sent + _logger.info("Firebase: sent %s/%s messages in chunk", sent, len(batch)) + return success_total + except Exception as exc: # catch firebase exceptions and log them + _logger.exception("Failed to send firebase notifications: %s", exc) + return 0 + + + +