[IMP] odex_mobile: add push notifications mixin

This commit is contained in:
Abdurrahman Saber 2025-09-20 01:24:37 +03:00
parent 6d53a4d550
commit 1b8f53c192
5 changed files with 86 additions and 102 deletions

View File

@ -374,11 +374,7 @@ class AttendanceController(http.Controller):
partner_id = emp.user_id.partner_id partner_id = emp.user_id.partner_id
partner_id.send_notification( partner_id.send_notification(
subject, msg, data=None, all_device=True) subject, msg, data=None, all_device=True)
data = { emp.send_push_notification(title=subject, body=msg)
'title':subject,
'body':msg,
}
emp.user_push_notification(data)
def create_log(self, employee, longitude, latitude): def create_log(self, employee, longitude, latitude):
attendance = http.request.env['attendance.log'].create({ attendance = http.request.env['attendance.log'].create({

View File

@ -10,3 +10,4 @@ from . import hr_firebase_notification
from . import base from . import base
from . import ir_property from . import ir_property
from . import resource from . import resource
from . import push_notification_mixin

View File

@ -4,79 +4,19 @@ from odoo import models,fields,api,_
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
import random import random
import json import json
import json, requests
import json, requests, base64
import google.auth.transport.requests import google.auth.transport.requests
from google.oauth2 import service_account
BASE_URL = 'https://fcm.googleapis.com'
SCOPES = ['https://www.googleapis.com/auth/firebase.messaging']
import tempfile
import os
class HrEmployee(models.Model): class HrEmployee(models.Model):
_inherit = 'hr.employee' _name = 'hr.employee'
_inherit = ['hr.employee', 'push.notification.mixin']
device_id = fields.Char(string="Employee Device ") device_id = fields.Char(string="Employee Device ")
fcm_token = fields.Char(string='FCM Token')
attendance_log_ids = fields.One2many('attendance.log','employee_id',string="Attendance Log") attendance_log_ids = fields.One2many('attendance.log','employee_id',string="Attendance Log")
message_sent = fields.Boolean(string="Message Sent", default=False) message_sent = fields.Boolean(string="Message Sent", default=False)
# Used internally by the API # Used internally by the API
last_active_time = fields.Datetime(readonly=True) last_active_time = fields.Datetime(readonly=True)
attendance_zone_id = fields.Many2many('attendance.zone', string='Attendance Zone') attendance_zone_id = fields.Many2many('attendance.zone', string='Attendance Zone')
def user_push_notification(self, notification):
def _get_access_token(json_file):
"""Retrieve a valid access token that can be used to authorize requests.
:return: Access token.
"""
credentials = service_account.Credentials.from_service_account_file(
json_file, scopes=SCOPES)
request = google.auth.transport.requests.Request()
credentials.refresh(request)
return credentials.token
try:
json_file_name = 'service-account'
base64_service_account = base64.decodebytes(self.env.user.company_id.service_account)
service_account_json = json.loads(base64_service_account)
with tempfile.TemporaryDirectory() as temp_dir:
temp_file_path = os.path.join(temp_dir, json_file_name)
with open(temp_file_path, 'w') as temp_file:
temp_file.write(base64_service_account.decode('UTF-8'))
header = {
'Content-Type': 'application/json',
'Authorization': 'Bearer %s' % (_get_access_token(temp_file_path))
}
body = json.dumps({
"message": {
"token": self.fcm_token,
"notification": notification,
"android": {
"notification": {
"sound": "default"
}
},
"apns": {
"payload": {
"aps": {
"sound": "default"
}
}
}
}
})
FCM_ENDPOINT = 'v1/projects/' + service_account_json['project_id'] + '/messages:send'
FCM_URL = BASE_URL + '/' + FCM_ENDPOINT
respons = requests.post(url=FCM_URL, data=body, headers=header)
return True
except Exception as e:
return False
def create_employee_notification(self): def create_employee_notification(self):
emp_notif_obj = self.env['employee.notification'] emp_notif_obj = self.env['employee.notification']
holiday_obj = self.env['hr.holidays'] holiday_obj = self.env['hr.holidays']

View File

@ -0,0 +1,78 @@
import json, requests, base64
import tempfile
import os
import logging
from odoo import models, fields, api, _
from odoo.exceptions import UserError
import google.auth.transport.requests
from google.oauth2 import service_account
BASE_URL = 'https://fcm.googleapis.com'
SCOPES = ['https://www.googleapis.com/auth/firebase.messaging']
_logger = logging.getLogger(__name__)
class PushNotificationMixin(models.AbstractModel):
_name = 'push.notification.mixin'
_description = 'Push Notification Mixin'
fcm_token = fields.Char(string='FCM Token')
def send_push_notification(self, title, body):
def _get_access_token(json_file):
"""Retrieve a valid access token that can be used to authorize requests.
:return: Access token.
"""
credentials = service_account.Credentials.from_service_account_file(
json_file, scopes=SCOPES)
request = google.auth.transport.requests.Request()
credentials.refresh(request)
return credentials.token
for rec in self:
if not rec.fcm_token:
raise UserError(_("FCM Token is required"))
if not self.env.user.company_id.service_account:
raise UserError(_("Firebase Service Account file is required"))
try:
json_file_name = 'service-account'
base64_service_account = base64.decodebytes(self.env.user.company_id.service_account)
service_account_json = json.loads(base64_service_account)
with tempfile.TemporaryDirectory() as temp_dir:
temp_file_path = os.path.join(temp_dir, json_file_name)
with open(temp_file_path, 'w') as temp_file:
temp_file.write(base64_service_account.decode('UTF-8'))
header = {
'Content-Type': 'application/json',
'Authorization': 'Bearer %s' % (_get_access_token(temp_file_path))
}
body = json.dumps({
"message": {
"token": rec.fcm_token,
"notification": {
"title": title,
"body": body
},
"android": {
"notification": {
"sound": "default"
}
},
"apns": {
"payload": {
"aps": {
"sound": "default"
}
}
}
}
})
FCM_ENDPOINT = 'v1/projects/' + service_account_json['project_id'] + '/messages:send'
FCM_URL = BASE_URL + '/' + FCM_ENDPOINT
requests.post(url=FCM_URL, data=body, headers=header)
except Exception as e:
_logger.error(f"Failed to send push notification for {rec.name}: {e}")

View File

@ -6,22 +6,13 @@ from odoo import models, fields, api
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
class Partner(models.Model): class Partner(models.Model):
_inherit = 'res.partner' _name = 'res.partner'
_inherit = ['res.partner', 'push.notification.mixin']
firebase_registration_ids = fields.One2many( firebase_registration_ids = fields.One2many(
"firebase.registration", "partner_id", readonly=True "firebase.registration", "partner_id", readonly=True
) )
def send_msg(self, partner_ids, msg, subject):
emp = self.env['hr.employee'].sudo().search([('user_id', 'in', partner_ids.user_ids.ids)])
if emp.user_id.partner_id:
partner_id = emp.user_id.partner_id
# partner_id.send_notification(subject, msg, data=None, all_device=True)
data = {
'title':subject,
'body':msg,
}
emp.user_push_notification(data)
def send_notification(self, message_title, message_body, data=None, all_device=True): def send_notification(self, message_title, message_body, data=None, all_device=True):
notification_data = { notification_data = {
"title": str(message_title), "title": str(message_title),
@ -34,7 +25,7 @@ class Partner(models.Model):
notification = self.env['firebase.notification'].sudo().create(notification_data) notification = self.env['firebase.notification'].sudo().create(notification_data)
if all_device: if all_device:
self.send_msg(notification.partner_ids,str(message_title),str(message_body)) notification.partner_ids.send_push_notification(str(message_title), str(message_body))
for reg in self.firebase_registration_ids: for reg in self.firebase_registration_ids:
reg.with_context(lang=self.lang).send_message( reg.with_context(lang=self.lang).send_message(
message_title, message_title,
@ -57,25 +48,3 @@ class Partner(models.Model):
message_body, message_body,
data=data data=data
) )
def user_push_notification(self, fcm_token):
url = "https://fcm.googleapis.com/fcm/send"
headers = {
'Content-Type': 'application/json',
'Authorization': f'key={self.env.user.company_id.fcm_server_key}'
}
body = json.dumps({
"to": fcm_token,
"direct_boot_ok": True,
"notification": {
"title": "Test",
"body": "test"
}
})
try:
response = requests.post(url=url, data=body, headers=headers)
response.raise_for_status()
return True
except requests.exceptions.RequestException as e:
_logger.error(f"Failed to send push notification: {e}")
return False