Browse Source

Oct 06 : [RMV] Module Removed 'odoo_webhook'

pull/295/head
RisvanaCybro 2 years ago
parent
commit
5982ae6c20
  1. 46
      odoo_webhook/README.rst
  2. 22
      odoo_webhook/__init__.py
  3. 44
      odoo_webhook/__manifest__.py
  4. 7
      odoo_webhook/doc/RELEASE_NOTES.md
  5. 23
      odoo_webhook/models/__init__.py
  6. 540
      odoo_webhook/models/models.py
  7. 41
      odoo_webhook/models/webhook_webhook.py
  8. 2
      odoo_webhook/security/ir.model.access.csv
  9. BIN
      odoo_webhook/static/description/assets/icons/check.png
  10. BIN
      odoo_webhook/static/description/assets/icons/chevron.png
  11. BIN
      odoo_webhook/static/description/assets/icons/cogs.png
  12. BIN
      odoo_webhook/static/description/assets/icons/consultation.png
  13. BIN
      odoo_webhook/static/description/assets/icons/ecom-black.png
  14. BIN
      odoo_webhook/static/description/assets/icons/education-black.png
  15. BIN
      odoo_webhook/static/description/assets/icons/hotel-black.png
  16. BIN
      odoo_webhook/static/description/assets/icons/license.png
  17. BIN
      odoo_webhook/static/description/assets/icons/lifebuoy.png
  18. BIN
      odoo_webhook/static/description/assets/icons/manufacturing-black.png
  19. BIN
      odoo_webhook/static/description/assets/icons/pos-black.png
  20. BIN
      odoo_webhook/static/description/assets/icons/puzzle.png
  21. BIN
      odoo_webhook/static/description/assets/icons/restaurant-black.png
  22. BIN
      odoo_webhook/static/description/assets/icons/service-black.png
  23. BIN
      odoo_webhook/static/description/assets/icons/trading-black.png
  24. BIN
      odoo_webhook/static/description/assets/icons/training.png
  25. BIN
      odoo_webhook/static/description/assets/icons/update.png
  26. BIN
      odoo_webhook/static/description/assets/icons/user.png
  27. BIN
      odoo_webhook/static/description/assets/icons/wrench.png
  28. BIN
      odoo_webhook/static/description/assets/misc/categories.png
  29. BIN
      odoo_webhook/static/description/assets/misc/check-box.png
  30. BIN
      odoo_webhook/static/description/assets/misc/compass.png
  31. BIN
      odoo_webhook/static/description/assets/misc/corporate.png
  32. BIN
      odoo_webhook/static/description/assets/misc/customer-support.png
  33. BIN
      odoo_webhook/static/description/assets/misc/cybrosys-logo.png
  34. BIN
      odoo_webhook/static/description/assets/misc/features.png
  35. BIN
      odoo_webhook/static/description/assets/misc/logo.png
  36. BIN
      odoo_webhook/static/description/assets/misc/pictures.png
  37. BIN
      odoo_webhook/static/description/assets/misc/pie-chart.png
  38. BIN
      odoo_webhook/static/description/assets/misc/right-arrow.png
  39. BIN
      odoo_webhook/static/description/assets/misc/star.png
  40. BIN
      odoo_webhook/static/description/assets/misc/support.png
  41. BIN
      odoo_webhook/static/description/assets/misc/whatsapp.png
  42. BIN
      odoo_webhook/static/description/assets/modules/l1.png
  43. BIN
      odoo_webhook/static/description/assets/modules/l2.png
  44. BIN
      odoo_webhook/static/description/assets/modules/l3.png
  45. BIN
      odoo_webhook/static/description/assets/modules/l4.png
  46. BIN
      odoo_webhook/static/description/assets/modules/l5.png
  47. BIN
      odoo_webhook/static/description/assets/modules/l6.png
  48. BIN
      odoo_webhook/static/description/assets/screenshots/Screenshot1.png
  49. BIN
      odoo_webhook/static/description/assets/screenshots/Screenshot2.png
  50. BIN
      odoo_webhook/static/description/assets/screenshots/Screenshot3.png
  51. BIN
      odoo_webhook/static/description/assets/screenshots/Screenshot4.png
  52. BIN
      odoo_webhook/static/description/assets/screenshots/Screenshot5.png
  53. BIN
      odoo_webhook/static/description/assets/screenshots/Screenshot6.png
  54. BIN
      odoo_webhook/static/description/assets/screenshots/Screenshot7.png
  55. BIN
      odoo_webhook/static/description/assets/screenshots/Screenshot8.png
  56. BIN
      odoo_webhook/static/description/assets/screenshots/Screenshot9.png
  57. BIN
      odoo_webhook/static/description/assets/screenshots/hero.gif
  58. BIN
      odoo_webhook/static/description/banner.png
  59. BIN
      odoo_webhook/static/description/icon.png
  60. 671
      odoo_webhook/static/description/index.html
  61. 45
      odoo_webhook/views/webhook_webhook_views.xml

46
odoo_webhook/README.rst

@ -1,46 +0,0 @@
.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg
:target: https://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
Odoo Webhook
============
Odoo will send payload to the registered urls when an event occurs on the selected model.
Configuration
=============
* No additional configurations needed
Company
-------
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__
License
-------
GNU AFFERO GENERAL PUBLIC LICENSE, Version 3 (AGPLv3)
(https://www.gnu.org/licenses/agpl-3.0-standalone.html)
Credits
-------
Developer: (V16) Unnimaya C O, Contact: odoo@cybrosys.com
Contacts
--------
* Mail Contact : odoo@cybrosys.com
* Website : https://cybrosys.com
Bug Tracker
-----------
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported.
Maintainer
==========
.. image:: https://cybrosys.com/images/logo.png
:target: https://cybrosys.com
This module is maintained by Cybrosys Technologies.
For support and more information, please visit `Our Website <https://cybrosys.com/>`__
Further information
===================
HTML Description: `<static/description/index.html>`__

22
odoo_webhook/__init__.py

@ -1,22 +0,0 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Unnimaya C O (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
from . import models

44
odoo_webhook/__manifest__.py

@ -1,44 +0,0 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Unnimaya C O (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
{
'name': "Odoo Webhook",
'version': '16.0.1.0.0',
'category': 'Productivity',
'summary': """Odoo will send payload to the registered urls when an
event occurs on the selected model.""",
'description': """Webhooks are a potent tool for creating integrations
across various services and applications. A payload will be posted to
the registered urls when an event occurs on the chosen model.""",
'author': 'Cybrosys Techno Solutions',
'company': 'Cybrosys Techno Solutions',
'maintainer': 'Cybrosys Techno Solutions',
'website': 'https://www.cybrosys.com',
'data': [
'security/ir.model.access.csv',
'views/webhook_webhook_views.xml',
],
'images': ['static/description/banner.png'],
'license': 'AGPL-3',
'installable': True,
'auto_install': False,
'application': False,
}

7
odoo_webhook/doc/RELEASE_NOTES.md

@ -1,7 +0,0 @@
## Module <odoo_webhook>
#### 29.09.2023
#### Version 16.0.1.0.0
#### ADD
- Initial commit for Odoo Webhook

23
odoo_webhook/models/__init__.py

@ -1,23 +0,0 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Unnimaya C O (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
from . import models
from . import webhook_webhook

540
odoo_webhook/models/models.py

@ -1,540 +0,0 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Unnimaya C O (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
import json
import requests
from collections import defaultdict
from operator import attrgetter
from requests.exceptions import MissingSchema
from odoo import api, _, SUPERUSER_ID
from odoo.exceptions import UserError, ValidationError, AccessError
from odoo.models import BaseModel, _unlink, LOG_ACCESS_COLUMNS, \
INSERT_BATCH_SIZE, SQL_DEFAULT
from odoo.tools import OrderedSet, split_every, attrgetter, clean_context
@api.model
def _create(self, data_list):
""" Override _create method for sending the payload to the registered
webhook url. When a new record is added to the model, it will check
whether the model is added to webhook_webhook model. If it is added,
the payload will be posted to the create_url."""
assert data_list
cr = self.env.cr
# insert rows in batches of maximum INSERT_BATCH_SIZE
ids = [] # ids of created records
other_fields = OrderedSet() # non-column fields
for data_sublist in split_every(INSERT_BATCH_SIZE, data_list):
stored_list = [data['stored'] for data in data_sublist]
fnames = sorted({name for stored in stored_list for name in stored})
columns = []
rows = [[] for _ in stored_list]
for fname in fnames:
field = self._fields[fname]
if field.column_type:
columns.append(fname)
for stored, row in zip(stored_list, rows):
if fname in stored:
colval = field.convert_to_column(stored[fname], self,
stored)
if field.translate is True and colval:
if 'en_US' not in colval.adapted:
colval.adapted['en_US'] = next(
iter(colval.adapted.values()))
row.append(colval)
else:
row.append(SQL_DEFAULT)
else:
other_fields.add(field)
if field.type == 'properties':
# force calling fields.create for properties field because
# we might want to update the parent definition
other_fields.add(field)
if not columns:
# manage the case where we create empty records
columns = ['id']
for row in rows:
row.append(SQL_DEFAULT)
header = ", ".join(f'"{column}"' for column in columns)
template = ", ".join("%s" for _ in rows)
cr.execute(
f'INSERT INTO "{self._table}" ({header}) VALUES {template} '
f'RETURNING "id"',
[tuple(row) for row in rows],
)
ids.extend(id_ for id_, in cr.fetchall())
# put the new records in cache, and update inverse fields, for many2one
#
# cachetoclear is an optimization to avoid modified()'s cost until
# other_fields are processed
cachetoclear = []
records = self.browse(ids)
inverses_update = defaultdict(list) # {(field, value): ids}
common_set_vals = set(
LOG_ACCESS_COLUMNS + [self.CONCURRENCY_CHECK_FIELD, 'id',
'parent_path'])
for data, record in zip(data_list, records):
data['record'] = record
# DLE P104: test_inherit.py, test_50_search_one2many
vals = dict(
{k: v for d in data['inherited'].values() for k, v in d.items()},
**data['stored'])
set_vals = common_set_vals.union(vals)
for field in self._fields.values():
if field.type in ('one2many', 'many2many'):
self.env.cache.set(record, field, ())
elif field.related and not field.column_type:
self.env.cache.set(record, field,
field.convert_to_cache(None, record))
# DLE P123: `test_adv_activity`, `test_message_assignation_inbox`,
# `test_message_log`, `test_create_mail_simple`, ...
# Set `mail.message.parent_id` to False in cache, so it doesn't do
# the useless SELECT when computing the modified of `child_ids`
# in other words, if `parent_id` is not set, no other message
# `child_ids` are impacted.
# + avoid the fetch of fields which are False. e.g. if a boolean
# field is not passed in vals and as no default set in the field
# attributes, then we know it can be set to False in the cache in
# the case of create.
elif field.name not in set_vals and not field.compute:
self.env.cache.set(record, field,
field.convert_to_cache(None, record))
for fname, value in vals.items():
field = self._fields[fname]
if field.type in ('one2many', 'many2many'):
cachetoclear.append((record, field))
else:
cache_value = field.convert_to_cache(value, record)
self.env.cache.set(record, field, cache_value)
if field.type in ('many2one', 'many2one_reference') and \
self.pool.field_inverses[field]:
inverses_update[(field, cache_value)].append(record.id)
for (field, value), record_ids in inverses_update.items():
field._update_inverses(self.browse(record_ids), value)
# update parent_path
records._parent_store_create()
# protect fields being written against recomputation
protected = [(data['protected'], data['record']) for data in data_list]
with self.env.protecting(protected):
# mark computed fields as todo
records.modified(self._fields, create=True)
if other_fields:
# discard default values from context for other fields
others = records.with_context(clean_context(self._context))
for field in sorted(other_fields, key=attrgetter('_sequence')):
field.create([
(other, data['stored'][field.name])
for other, data in zip(others, data_list)
if field.name in data['stored']
])
# mark fields to recompute
records.modified([field.name for field in other_fields],
create=True)
# if value in cache has not been updated by other_fields, remove it
for record, field in cachetoclear:
if self.env.cache.contains(record,
field) and not self.env.cache.get(record,
field):
self.env.cache.remove(record, field)
# check Python constraints for stored fields
records._validate_fields(
name for data in data_list for name in data['stored'])
records.check_access_rule('create')
webhook = self.env['webhook.webhook'].search(
[('model_id', '=', self.env['ir.model'].sudo().search(
[('model', '=', records._name)]).id)]).filtered(
lambda r: r.create_url).mapped(
'create_url')
if webhook:
# Create payload if the model is added to webhook
for rec in records:
val_list = rec.search_read([('id', '=', rec.id)])
for item in val_list[0].keys():
field = (self.env['ir.model.fields'].sudo().search(
[('model', '=', rec._name), ('name', '=', item)]))
if field.ttype == 'binary':
if val_list[0][field.name]:
base_url = self.env[
'ir.config_parameter'].sudo().get_param(
'web.base.url')
val_list[0][field.name] = (
f'{base_url}/web/image/{self._name}/'
f'{val_list[0]["id"]}'
f'/{field.name}')
for item in webhook:
# Post payload to the registered url
requests.post(item, data=json.dumps(val_list[0],
default=str),
headers={
'Content-Type': 'application/json'})
try:
requests.post(item,
data=json.dumps(val_list[0], default=str),
headers={'Content-Type': 'application/json'})
except MissingSchema:
raise ValidationError("Please check the Webhook Url for "
"Create Event")
return records
def unlink(self):
"""Override unlink method for sending the payload to the registered
webhook url. When a record is deleted from a model, it will check
whether the model is added to the webhook_webhook model. If it is added,
the payload will be posted to the delete_url."""
if not self:
return True
self.check_access_rights('unlink')
self.check_access_rule('unlink')
from odoo.addons.base.models.ir_model import MODULE_UNINSTALL_FLAG
for func in self._ondelete_methods:
# func._ondelete is True if it should be called during uninstallation
if func._ondelete or not self._context.get(MODULE_UNINSTALL_FLAG):
func(self)
# TO FIX: this avoids an infinite loop when trying to recompute a
# field, which triggers the recomputation of another field using the
# same compute function, which then triggers again the computation
# of those two fields
for field in self._fields.values():
self.env.remove_to_compute(field, self)
self.env.flush_all()
cr = self._cr
Data = self.env['ir.model.data'].sudo().with_context({})
Defaults = self.env['ir.default'].sudo()
Property = self.env['ir.property'].sudo()
Attachment = self.env['ir.attachment'].sudo()
ir_property_unlink = Property
ir_model_data_unlink = Data
ir_attachment_unlink = Attachment
# mark fields that depend on 'self' to recompute them after 'self' has
# been deleted (like updating a sum of lines after deleting one line)
with self.env.protecting(self._fields.values(), self):
self.modified(self._fields, before=True)
webhook = self.env['webhook.webhook'].search(
[('model_id', '=', self.env['ir.model'].sudo().search(
[('model', '=', self._name)]).id)]).filtered(
lambda r: r.delete_url).mapped('delete_url')
# Create payload of the model is added to webhook
if webhook.delete_url:
val_list = []
for rec in self:
val_list = rec.search_read([('id', '=', rec.id)])
for item in val_list[0].keys():
field = (self.env['ir.model.fields'].sudo().search(
[('model', '=', rec._name), ('name', '=', item)]))
if field.ttype == 'binary':
if val_list[0][field.name]:
base_url = self.env[
'ir.config_parameter'].sudo().get_param(
'web.base.url')
val_list[0][field.name] = (f'{base_url}/web/image/'
f'{self._name}/{rec.id}'
f'/{field.name}')
for rec in webhook:
# Post payload to the registered url
try:
requests.post(rec, data=json.dumps(val_list[0], default=str),
headers={'Content-Type': 'application/json'})
except MissingSchema:
raise ValidationError(_("Please check the Webhook Url for "
"Delete "
"Event"))
for sub_ids in cr.split_for_in_conditions(self.ids):
records = self.browse(sub_ids)
# Check if the records are used as default properties.
refs = [f'{self._name},{id_}' for id_ in sub_ids]
if Property.search(
[('res_id', '=', False), ('value_reference', 'in', refs)],
limit=1):
raise UserError(
_('Unable to delete this document because it is used as a '
'default property'))
# Delete the records' properties.
ir_property_unlink |= Property.search([('res_id', 'in', refs)])
query = f'DELETE FROM "{self._table}" WHERE id IN %s'
cr.execute(query, (sub_ids,))
# Removing the ir_model_data reference if the record being deleted
# is a record created by xml/csv file, as these are not connected
# with real database foreign keys, and would be dangling references.
#
# Note: the following steps are performed as superuser to avoid
# access rights restrictions, and with no context to avoid possible
# side effects during admin calls.
data = Data.search(
[('model', '=', self._name), ('res_id', 'in', sub_ids)])
ir_model_data_unlink |= data
# For the same reason, remove the defaults having some of the
# records as value
Defaults.discard_records(records)
# For the same reason, remove the relevant records in ir_attachment
# (the search is performed with sql as the search method of
# ir_attachment is overridden to hide attachments of deleted
# records)
query = ('SELECT id FROM ir_attachment WHERE res_model=%s AND'
' res_id IN %s')
cr.execute(query, (self._name, sub_ids))
ir_attachment_unlink |= Attachment.browse(
row[0] for row in cr.fetchall())
# invalidate the *whole* cache, since the orm does not handle all
# changes made in the database, like cascading delete!
self.env.invalidate_all(flush=False)
if ir_property_unlink:
ir_property_unlink.unlink()
if ir_model_data_unlink:
ir_model_data_unlink.unlink()
if ir_attachment_unlink:
ir_attachment_unlink.unlink()
# DLE P93: flush after unlink, for recompute fields depending on
# the modified of unlink
self.env.flush_all()
# auditing: deletions are infrequent and leave no trace in the database
_unlink.info('User #%s deleted %s records with IDs: %r', self._uid,
self._name, self.ids)
return True
def write(self, vals):
""" write(vals)
Updates all records in ``self`` with the provided values.
:param dict vals: fields to update and the value to set on them
:raise AccessError: if user is not allowed to modify the specified
records/fields
:raise ValidationError: if invalid values are specified for selection fields
:raise UserError: if a loop would be created in a hierarchy of objects a
result of the operation (such as setting an object as its own parent)
* For numeric fields (:class:`~odoo.fields.Integer`,
:class:`~odoo.fields.Float`) the value should be of the
corresponding type
* For :class:`~odoo.fields.Boolean`, the value should be a
:class:`python:bool`
* For :class:`~odoo.fields.Selection`, the value should match the
selection values (generally :class:`python:str`, sometimes
:class:`python:int`)
* For :class:`~odoo.fields.Many2one`, the value should be the
database identifier of the record to set
* The expected value of a :class:`~odoo.fields.One2many` or
:class:`~odoo.fields.Many2many` relational field is a list of
:class:`~odoo.fields.Command` that manipulate the relation the
implement. There are a total of 7 commands:
:meth:`~odoo.fields.Command.create`,
:meth:`~odoo.fields.Command.update`,
:meth:`~odoo.fields.Command.delete`,
:meth:`~odoo.fields.Command.unlink`,
:meth:`~odoo.fields.Command.link`,
:meth:`~odoo.fields.Command.clear`, and
:meth:`~odoo.fields.Command.set`.
* For :class:`~odoo.fields.Date` and `~odoo.fields.Datetime`,
the value should be either a date(time), or a string.
.. warning::
If a string is provided for Date(time) fields,
it must be UTC-only and formatted according to
:const:`odoo.tools.misc.DEFAULT_SERVER_DATE_FORMAT` and
:const:`odoo.tools.misc.DEFAULT_SERVER_DATETIME_FORMAT`
* Other non-relational fields use a string for value
"""
if not self:
return True
self.check_access_rights('write')
self.check_field_access_rights('write', vals.keys())
self.check_access_rule('write')
env = self.env
bad_names = {'id', 'parent_path'}
if self._log_access:
# the superuser can set log_access fields while loading registry
if not (self.env.uid == SUPERUSER_ID and not self.pool.ready):
bad_names.update(LOG_ACCESS_COLUMNS)
# set magic fields
vals = {key: val for key, val in vals.items() if key not in bad_names}
if self._log_access:
vals.setdefault('write_uid', self.env.uid)
vals.setdefault('write_date', self.env.cr.now())
field_values = [] # [(field, value)]
determine_inverses = defaultdict(list) # {inverse: fields}
fnames_modifying_relations = []
protected = set()
check_company = False
for fname, value in vals.items():
field = self._fields.get(fname)
if not field:
raise ValueError(
"Invalid field %r on model %r" % (fname, self._name))
field_values.append((field, value))
if field.inverse:
if field.type in ('one2many', 'many2many'):
# The written value is a list of commands that must applied
# on the field's current value. Because the field is
# protected while being written, the field's current value
# will not be computed and default to an empty recordset. So
# make sure the field's value is in cache before writing, in
# order to avoid an inconsistent update.
self[fname]
determine_inverses[field.inverse].append(field)
if self.pool.is_modifying_relations(field):
fnames_modifying_relations.append(fname)
if field.inverse or (field.compute and not field.readonly):
if field.store or field.type not in ('one2many', 'many2many'):
# Protect the field from being recomputed while being
# inversed. In the case of non-stored x2many fields, the
# field's value may contain unexpeced new records (created
# by command 0). Those new records are necessary for
# inversing the field, but should no longer appear if the
# field is recomputed afterwards. Not protecting the field
# will automatically invalidate the field from the cache,
# forcing its value to be recomputed once dependencies are
# up-to-date.
protected.update(self.pool.field_computed.get(field, [field]))
if fname == 'company_id' or (field.relational and field.check_company):
check_company = True
# force the computation of fields that are computed with some assigned
# fields, but are not assigned themselves
to_compute = [field.name
for field in protected
if field.compute and field.name not in vals]
if to_compute:
self._recompute_recordset(to_compute)
# protect fields being written against recomputation
with env.protecting(protected, self):
# Determine records depending on values. When modifying a relational
# field, you have to recompute what depends on the field's values
# before and after modification. This is because the modification
# has an impact on the "data path" between a computed field and its
# dependency. Note that this double call to modified() is only
# necessary for relational fields.
#
# It is best explained with a simple example: consider two sales
# orders SO1 and SO2. The computed total amount on sales orders
# indirectly depends on the many2one field 'order_id' linking lines
# to their sales order. Now consider the following code:
#
# line = so1.line_ids[0] # pick a line from SO1
# line.order_id = so2 # move the line to SO2
#
# In this situation, the total amount must be recomputed on *both*
# sales order: the line's order before the modification, and the
# line's order after the modification.
self.modified(fnames_modifying_relations, before=True)
real_recs = self.filtered('id')
# field.write_sequence determines a priority for writing on fields.
# Monetary fields need their corresponding currency field in cache
# for rounding values. X2many fields must be written last, because
# they flush other fields when deleting lines.
for field, value in sorted(field_values,
key=lambda item: item[0].write_sequence):
field.write(self, value)
# determine records depending on new values
#
# Call modified after write, because the modified can trigger a
# search which can trigger a flush which can trigger a recompute
# which remove the field from the recompute list while all the
# values required for the computation could not be yet in cache.
# e.g. Write on `name` of `res.partner` trigger the recompute of
# `display_name`, which triggers a search on child_ids to find the
# childs to which the display_name must be recomputed, which
# triggers the flush of `display_name` because the _order of
# res.partner includes display_name. The computation of display_name
# is then done too soon because the parent_id was not yet written.
# (`test_01_website_reset_password_tour`)
self.modified(vals)
if self._parent_store and self._parent_name in vals:
self.flush_model([self._parent_name])
# validate non-inversed fields first
inverse_fields = [f.name for fs in determine_inverses.values() for f in
fs]
real_recs._validate_fields(vals, inverse_fields)
for fields in determine_inverses.values():
# write again on non-stored fields that have been invalidated
# from cache
for field in fields:
if not field.store and any(
self.env.cache.get_missing_ids(real_recs, field)):
field.write(real_recs, vals[field.name])
# inverse records that are not being computed
try:
fields[0].determine_inverse(real_recs)
except AccessError as e:
if fields[0].inherited:
description = self.env['ir.model']._get(self._name).name
raise AccessError(_(
"%(previous_message)s\n\nImplicitly accessed through "
"'%(document_kind)s' (%(document_model)s).",
previous_message=e.args[0],
document_kind=description,
document_model=self._name,
))
raise
# validate inversed fields
real_recs._validate_fields(inverse_fields)
if self._name != 'ir.module.module':
webhook = self.env['webhook.webhook'].search(
[('model_id', '=', self.env['ir.model'].sudo().search(
[('model', '=', self._name)]).id)]).filtered(
lambda r: r.edit_url).mapped('edit_url')
if webhook:
# Create payload of the model is added to webhook
for item in vals.keys():
field = (self.env['ir.model.fields'].sudo().search(
[('model', '=', self._name), ('name', '=', item)]))
if field.ttype == 'binary':
if vals[field.name]:
base_url = self.env[
'ir.config_parameter'].sudo().get_param(
'web.base.url')
vals[field.name] = (
f'{base_url}/web/image/{self._name}/{self.id}'
f'/{field.name}')
for item in webhook:
# Post payload to the registered url
try:
requests.post(item,
data=json.dumps(vals, default=str),
headers={'Content-Type': 'application/json'})
except MissingSchema:
raise ValidationError(_("Please check the Webhook Url for "
"Edit Event"))
if check_company and self._check_company_auto:
self._check_company()
return True
BaseModel._create = _create
BaseModel.unlink = unlink
BaseModel.write = write

41
odoo_webhook/models/webhook_webhook.py

@ -1,41 +0,0 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Unnimaya C O (odoo@cybrosys.com)
#
# You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
#
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
from odoo import fields, models
class WebhookWebhook(models.Model):
"""Model that holds the webhook model and the urls to receive the payload"""
_name = 'webhook.webhook'
_description = 'Webhook'
_rec_name = 'model_id'
model_id = fields.Many2one('ir.model', string='Model',
help='Choose the model')
create_url = fields.Char(string="Url for Create Event",
help="The URL to which payload to be send when a "
"new record is created")
edit_url = fields.Char(string="Url for Edit Event",
help="The URL to which payload to be send when a "
"record is modified")
delete_url = fields.Char(string="Url for Delete Event",
help="The URL to which payload to be send when a "
"record is deleted")

2
odoo_webhook/security/ir.model.access.csv

@ -1,2 +0,0 @@
id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
access_webhook_webhook_user,access.webhook.webhook.user,model_webhook_webhook,base.group_user,1,1,1,1
1 id name model_id/id group_id/id perm_read perm_write perm_create perm_unlink
2 access_webhook_webhook_user access.webhook.webhook.user model_webhook_webhook base.group_user 1 1 1 1

BIN
odoo_webhook/static/description/assets/icons/check.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

BIN
odoo_webhook/static/description/assets/icons/chevron.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 310 B

BIN
odoo_webhook/static/description/assets/icons/cogs.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

BIN
odoo_webhook/static/description/assets/icons/consultation.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

BIN
odoo_webhook/static/description/assets/icons/ecom-black.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 576 B

BIN
odoo_webhook/static/description/assets/icons/education-black.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 733 B

BIN
odoo_webhook/static/description/assets/icons/hotel-black.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 911 B

BIN
odoo_webhook/static/description/assets/icons/license.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

BIN
odoo_webhook/static/description/assets/icons/lifebuoy.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

BIN
odoo_webhook/static/description/assets/icons/manufacturing-black.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 673 B

BIN
odoo_webhook/static/description/assets/icons/pos-black.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 878 B

BIN
odoo_webhook/static/description/assets/icons/puzzle.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 653 B

BIN
odoo_webhook/static/description/assets/icons/restaurant-black.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 905 B

BIN
odoo_webhook/static/description/assets/icons/service-black.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 839 B

BIN
odoo_webhook/static/description/assets/icons/trading-black.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 427 B

BIN
odoo_webhook/static/description/assets/icons/training.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 627 B

BIN
odoo_webhook/static/description/assets/icons/update.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

BIN
odoo_webhook/static/description/assets/icons/user.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 988 B

BIN
odoo_webhook/static/description/assets/icons/wrench.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

BIN
odoo_webhook/static/description/assets/misc/categories.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

BIN
odoo_webhook/static/description/assets/misc/check-box.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

BIN
odoo_webhook/static/description/assets/misc/compass.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

BIN
odoo_webhook/static/description/assets/misc/corporate.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

BIN
odoo_webhook/static/description/assets/misc/customer-support.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

BIN
odoo_webhook/static/description/assets/misc/cybrosys-logo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

BIN
odoo_webhook/static/description/assets/misc/features.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 589 B

BIN
odoo_webhook/static/description/assets/misc/logo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

BIN
odoo_webhook/static/description/assets/misc/pictures.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

BIN
odoo_webhook/static/description/assets/misc/pie-chart.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

BIN
odoo_webhook/static/description/assets/misc/right-arrow.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 967 B

BIN
odoo_webhook/static/description/assets/misc/star.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

BIN
odoo_webhook/static/description/assets/misc/support.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

BIN
odoo_webhook/static/description/assets/misc/whatsapp.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

BIN
odoo_webhook/static/description/assets/modules/l1.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

BIN
odoo_webhook/static/description/assets/modules/l2.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 257 KiB

BIN
odoo_webhook/static/description/assets/modules/l3.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

BIN
odoo_webhook/static/description/assets/modules/l4.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

BIN
odoo_webhook/static/description/assets/modules/l5.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

BIN
odoo_webhook/static/description/assets/modules/l6.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

BIN
odoo_webhook/static/description/assets/screenshots/Screenshot1.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

BIN
odoo_webhook/static/description/assets/screenshots/Screenshot2.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

BIN
odoo_webhook/static/description/assets/screenshots/Screenshot3.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

BIN
odoo_webhook/static/description/assets/screenshots/Screenshot4.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

BIN
odoo_webhook/static/description/assets/screenshots/Screenshot5.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 333 KiB

BIN
odoo_webhook/static/description/assets/screenshots/Screenshot6.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

BIN
odoo_webhook/static/description/assets/screenshots/Screenshot7.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

BIN
odoo_webhook/static/description/assets/screenshots/Screenshot8.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

BIN
odoo_webhook/static/description/assets/screenshots/Screenshot9.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 291 KiB

BIN
odoo_webhook/static/description/assets/screenshots/hero.gif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 350 KiB

BIN
odoo_webhook/static/description/banner.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

BIN
odoo_webhook/static/description/icon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

671
odoo_webhook/static/description/index.html

@ -1,671 +0,0 @@
<div style="background-color: #714B67; min-height: 600px; width: 100%; padding: 15px; position: relative;">
<!-- TITLE BAR -->
<div class="d-flex align-items-center justify-content-between"
style="border-bottom: 1px solid #875A7B; padding: 15px; display: flex; justify-content: space-between; align-items: center;">
<img src="assets/misc/cybrosys-logo.png" width="42" height="42"
style="width: 42px; height: 42px;"/>
<div>
<div style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Community
</div>
<div style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Enterprise
</div>
</div>
</div>
<!-- END OF TITLE BAR -->
<div class="container">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12">
<!-- APP HERO -->
<h1 style="color: #FFFFFF; font-weight: bolder; font-size: 50px; text-align: center; margin-top: 50px;">
Odoo Webhook</h1>
<p style="color:#FFFFFF; padding: 8px 15px; text-align: center; font-size: 24px;">
Odoo Will Send Payload to the Registered Urls When
an Event Occurs on the Selected Model.
</p>
<!-- END OF APP HERO -->
<img src="assets/screenshots/hero.gif"
style="width: 75%; height: auto; position: absolute; margin-left: auto; margin-right: auto; top: 45%; left: 12%; right: auto;"/>
</div>
</div>
</div>
</div>
<!-- NAVIGATION SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px; margin-top: 300px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/compass.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Explore This
Module</h2>
</div>
<div class="row my-4" style="font-family: 'Montserrat', sans-serif;">
<div class="col-sm-12 col-md-6 my-3">
<a href="#overview">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Overview</span>
<span
style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">Learn
more about this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36"/>
</div>
</a>
</div>
<div class="col-sm-12 col-md-6 my-3">
<a href="#features">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Features</span>
<span
style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View
features of this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36"/>
</div>
</a>
</div>
<div class="col-sm-12 col-md-6 my-3">
<a href="#screenshots">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Screenshots</span>
<span
style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View
screenshots for this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36"/>
</div>
</a>
</div>
</div>
<!-- END OF NAVIGATION SECTION -->
<!-- OVERVIEW SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="overview">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/pie-chart.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Overview
</h2>
</div>
<div class="row"
style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;">
<div class="col-sm-12 py-4">
Webhooks are a potent tool for creating integrations across various
services and applications. A payload will be posted to the registered
url when an event occurs on the chosen model.
</div>
</div>
<!-- END OF OVERVIEW SECTION -->
<!-- FEATURES SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="features">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/features.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Features
</h2>
</div>
<div class="row"
style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;">
<div class="col-sm-12 col-md-6">
<div class="d-flex align-items-center"
style="margin-top: 40px; margin-bottom: 40px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span
style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Webhook can be generated on Create event of any model.</span>
</div>
<div class="d-flex align-items-center"
style="margin-top: 40px; margin-bottom: 40px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span
style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Webhook can be generated on Delete event of any model.</span>
</div>
<div class="d-flex align-items-center"
style="margin-top: 40px; margin-bottom: 40px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span
style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Webhook can be generated on Edit event of any model.</span>
</div>
</div>
</div>
<!-- END OF FEATURES SECTION -->
<!-- SCREENSHOTS SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;"
id="screenshots">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/pictures.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Screenshots
</h2>
</div>
<div class="row">
<div class="col-sm-12">
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Webhook Menu in General Settings</h3>
<img src="assets/screenshots/Screenshot1.png"
class="img-thumbnail"/>
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Create a Webhook.
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
Select the Model for which the Webhook needs to be generated.
Url for Create Event, Url
for Delete Event and Url for Edit Event can be
filled with your website's urls where the payload should be
received when Create, Delete or Edit event occurs on the
selected model.
</p>
<img src="assets/screenshots/Screenshot2.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
New Webhook for the Model Contact. </h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
As an example,
the urls provided by Webhook.site(www.webhook.site) are given
for the fields Url
for Create
Event, Url for Delete Event and Url for Edit Event.
</p>
<img src="assets/screenshots/Screenshot3.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Create New Contact.
</h3>
<img src="assets/screenshots/Screenshot4.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
The Payload for Create Event.
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
The payload received at the Url for Create Event after adding
the Contact. In our example, the payload is received at the url provided by
Webhook.site(www.webhook.site)
</p>
<img src="assets/screenshots/Screenshot5.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Edit a Contact.
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
Apply any modifications to the Contact. The Contact's Company
Name is added here.
</p>
<img src="assets/screenshots/Screenshot6.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Payload for Edit Event
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
Payload received at the Url for Edit Event after
modifying the record.
In our example, the payload is received at the url provided by
Webhook.site(www.webhook.site)
</p>
<img src="assets/screenshots/Screenshot7.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Delete a Contact
</h3>
<img src="assets/screenshots/Screenshot8.png"
class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Payload for Delete Event
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
Payload received at the Url for Delete Event after
deleting the record.
In our example, the payload is received at the url provided by
Webhook.site(www.webhook.site)
</p>
<img src="assets/screenshots/Screenshot9.png"
class="img-thumbnail">
</div>
</div>
</div>
<!-- END OF SCREENSHOTS SECTION -->
<!-- RELATED PRODUCTS -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/categories.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Related
Products
</h2>
</div>
<div class="row">
<div class="col-sm-12">
<div id="demo1" class="row carousel slide" data-ride="carousel">
<!-- The slideshow -->
<div class="carousel-inner" style="padding: 30px;">
<div class="carousel-item" style="min-height: 198.656px;">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/upcitemdb_integration/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/l1.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/education_erp_dashboard/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/l2.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/agriculture_management_odoo/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/l3.png">
</div>
</a>
</div>
</div>
<div class="carousel-item active"
style="min-height: 198.656px;">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/product_image_suggestion/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/l4.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/odoo_magento_2_4_5/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/l5.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/advanced_dynamic_dashboard/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/l6.png">
</div>
</a>
</div>
</div>
</div>
<!-- Left and right controls -->
<a class="carousel-control-prev" href="#demo1" data-slide="prev"
style="width:35px; color:#000"> <span
class="carousel-control-prev-icon"><i
class="fa fa-chevron-left"
style="font-size:24px"></i></span>
</a> <a class="carousel-control-next" href="#demo1"
data-slide="next" style="width:35px; color:#000">
<span class="carousel-control-next-icon"><i
class="fa fa-chevron-right"
style="font-size:24px"></i></span>
</a>
</div>
</div>
</div>
<!-- END OF RELATED PRODUCTS -->
<!-- OUR SERVICES -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/star.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Our Services
</h2>
</div>
<div class="container my-5">
<div class="row">
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #1dd1a1 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/cogs.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Customization</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #ff6b6b !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/wrench.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Implementation</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #6462CD !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/lifebuoy.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Support</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #ffa801 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/user.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Hire
Odoo
Developer</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #54a0ff !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/puzzle.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Integration</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #6d7680 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/update.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Migration</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #786fa6 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/consultation.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Consultancy</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #f8a5c2 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/training.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Implementation</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #e6be26 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/license.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Licensing Consultancy</h6>
</div>
</div>
</div>
<!--END OF OUR SERVICES -->
<!-- OUR INDUSTRIES -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/corporate.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Our
Industries
</h2>
</div>
<div class="container my-5">
<div class="row">
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/trading-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Trading
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Easily procure
and
sell your products</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/pos-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
POS
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Easy
configuration
and convivial experience</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/education-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Education
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
A platform for
educational management</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/manufacturing-black.png"
class="img-responsive mb-3" height="48px"
width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Manufacturing
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Plan, track and
schedule your operations</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/ecom-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
E-commerce &amp; Website
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Mobile
friendly,
awe-inspiring product pages</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/service-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Service Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Keep track of
services and invoice</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/restaurant-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Restaurant
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Run your bar or
restaurant methodically</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/hotel-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Hotel Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
An
all-inclusive
hotel management application</p>
</div>
</div>
</div>
</div>
<!-- END OF OUR INDUSTRIES -->
<!-- SUPPORT -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/customer-support.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Support
</h2>
</div>
<div class="container mt-5">
<div class="row">
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4"
style="background-color: #714B67; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="assets/misc/support.png" height="48" width="48"
style="width: 42px; height: 42px;"/>
</div>
<div>
<h4>Need Help?</h4>
<p style="line-height: 100%;">Got questions or need help?
Get in touch.</p>
<a href="mailto:odoo@cybrosys.com">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">
odoo@cybrosys.com</p>
</a>
</div>
</div>
</div>
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4"
style="background-color: #2AC44D; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="assets/misc/whatsapp.png" height="52" width="52"
style="width: 52px; height: 52px;"/>
</div>
<div>
<h4>WhatsApp</h4>
<p style="line-height: 100%;">Say hi to us on WhatsApp!</p>
<a href="https://api.whatsapp.com/send?phone=918606827707">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">
+91 86068
27707</p>
</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 my-5 d-flex justify-content-center align-items-center">
<img src="assets/misc/logo.png" width="144" height="31"
style="width:144px; height: 31px; margin-top: 40px;"/>
</div>
</div>
</div>
<!-- END OF SUPPORT -->

45
odoo_webhook/views/webhook_webhook_views.xml

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Webhook Webhook Form View-->
<record id="webhook_webhook_view_form" model="ir.ui.view">
<field name="name">webhook.webhook.view.form</field>
<field name="model">webhook.webhook</field>
<field name="priority" eval="20"/>
<field name="arch" type="xml">
<form>
<sheet name="Webhook">
<group>
<group>
<field name="model_id"/>
<field name="create_url"/>
</group>
<group>
<field name="delete_url"/>
<field name="edit_url"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<!-- Webhook Webhook Tree View-->
<record id="webhook_webhook_view_tree" model="ir.ui.view">
<field name="name">webhook.webhook.view.tree</field>
<field name="model">webhook.webhook</field>
<field name="priority" eval="20"/>
<field name="arch" type="xml">
<tree>
<field name="model_id"/>
</tree>
</field>
</record>
<!-- Webhook Menu Action-->
<record id="webhook_webhook_action" model="ir.actions.act_window">
<field name="name">Webhook</field>
<field name="res_model">webhook.webhook</field>
<field name="view_mode">tree,form</field>
</record>
<!-- Webhook Menu-->
<menuitem id="webhook_webhook_menu" name="Webhook"
parent="base.menu_automation" action="webhook_webhook_action"/>
</odoo>
Loading…
Cancel
Save