@ -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 |
|
||||
|
|
||||
Product Data Feed Generation |
|
||||
============================ |
|
||||
Generating a Product Catalog Feeds Sharing Link |
|
||||
|
|
||||
Configuration |
|
||||
============= |
|
||||
* No additional configurations needed |
|
||||
|
|
||||
License |
|
||||
------- |
|
||||
Affero General Public License v3.0 (AGPL v3) |
|
||||
(https://www.gnu.org/licenses/agpl-3.0-standalone.html) |
|
||||
|
|
||||
Company |
|
||||
------- |
|
||||
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__ |
|
||||
|
|
||||
Credits |
|
||||
------- |
|
||||
* Developer: (V17) Subina P, 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>`__ |
|
@ -1,22 +0,0 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
############################################################################### |
|
||||
# |
|
||||
# Cybrosys Technologies Pvt. Ltd. |
|
||||
# |
|
||||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|
||||
# Author: Subina P (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 controllers, models |
|
@ -1,54 +0,0 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
############################################################################### |
|
||||
# |
|
||||
# Cybrosys Technologies Pvt. Ltd. |
|
||||
# |
|
||||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|
||||
# Author: Subina P (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': 'Product Data Feed Generation', |
|
||||
'version': '17.0.1.0.0', |
|
||||
'category': 'eCommerce', |
|
||||
'summary': 'Help to create the catalog for promoting your sale', |
|
||||
'description': 'Using this module we have to promote and market our sales' |
|
||||
' through facebook and instagram for using the catalog of ' |
|
||||
'our product. Many of the businesses sell or advertise ' |
|
||||
'their product through facebook and instagram. So they' |
|
||||
' need a catalog that contains the information about your ' |
|
||||
'products. In this module generate the product data feed ' |
|
||||
'file for the facebook commerce manager in automatic ' |
|
||||
'mode(by URL). After adding the data feed URL on facebook ' |
|
||||
'you will be able to promote your product in sale channels ,' |
|
||||
' on facebook shops, instagram shopping, with dynamic ads,' |
|
||||
' and more.', |
|
||||
'author': 'Cybrosys Techno Solutions', |
|
||||
'company': 'Cybrosys Techno Solutions', |
|
||||
'maintainer': 'Cybrosys Techno Solutions', |
|
||||
'website': 'https://www.cybrosys.com', |
|
||||
'depends': ['website_sale', 'product', 'mail', 'stock'], |
|
||||
'data': [ |
|
||||
'security/ir.model.access.csv', |
|
||||
'views/product_data_feed_views.xml', |
|
||||
'views/product_data_feed_columns_views.xml', |
|
||||
'views/field_column_value_views.xml', |
|
||||
], |
|
||||
'images': ['static/description/banner.jpg'], |
|
||||
'license': 'AGPL-3', |
|
||||
'installable': True, |
|
||||
'application': False, |
|
||||
'auto_install': False |
|
||||
} |
|
@ -1,22 +0,0 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
############################################################################### |
|
||||
# |
|
||||
# Cybrosys Technologies Pvt. Ltd. |
|
||||
# |
|
||||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|
||||
# Author: Subina P (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 odoo_fb_insta_product_data_feed |
|
@ -1,95 +0,0 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
############################################################################### |
|
||||
# |
|
||||
# Cybrosys Technologies Pvt. Ltd. |
|
||||
# |
|
||||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|
||||
# Author: Subina P (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 csv |
|
||||
from six import StringIO |
|
||||
from odoo import http |
|
||||
from odoo.http import request |
|
||||
|
|
||||
|
|
||||
class ProductData(http.Controller): |
|
||||
"""This controller handle for downloading the catalog csv file""" |
|
||||
def generate_formatted_file_content(self, columns, item_filter, record): |
|
||||
"""Generating the file content""" |
|
||||
# Apply the filter criteria and fetch the relevant items |
|
||||
filtered_items = request.env[record.used_model].search(item_filter) |
|
||||
formatted_rows = [] |
|
||||
# Iterate over each item and generate a row of values |
|
||||
for item in filtered_items: |
|
||||
row = [] |
|
||||
for column in columns: |
|
||||
if column.type == 'Model Field': |
|
||||
# Access the field value directly |
|
||||
value = getattr(item, column.value_id.name, '') |
|
||||
elif column.type == 'Special': |
|
||||
if column.special_type == 'product_availability': |
|
||||
# Access the product's on-hand quantity |
|
||||
on_hand_qty = item.qty_available |
|
||||
# Set value based on on-hand quantity |
|
||||
if on_hand_qty == 0: |
|
||||
value = 'out of stock' |
|
||||
else: |
|
||||
value = 'in stock' |
|
||||
elif column.special_type == 'qty': |
|
||||
value = item.qty_available |
|
||||
elif column.special_type == 'product_price': |
|
||||
value = item.standard_price |
|
||||
elif column.special_type == 'disc_price': |
|
||||
value = item.list_price |
|
||||
elif column.special_type == 'price_without_tax': |
|
||||
value = item.list_price |
|
||||
elif column.special_type == 'price_currency': |
|
||||
value = self.currency_id.name |
|
||||
elif column.type == 'Text': |
|
||||
value = column.value |
|
||||
elif column.type == 'Value': |
|
||||
value = column.field_value_id.column_name |
|
||||
else: |
|
||||
value = column.value |
|
||||
row.append(value) |
|
||||
formatted_rows.append(row) |
|
||||
return formatted_rows |
|
||||
|
|
||||
@http.route(['/product_data/<int:id>/<name>', |
|
||||
'/product_data/<name>' |
|
||||
], type="http", |
|
||||
auth='public') |
|
||||
def product_data(self, id, name): |
|
||||
"""Making the product data into a CSV formate.""" |
|
||||
record = request.env['product.data.feed'].sudo().browse(id) |
|
||||
column_ids = record.feed_columns_line_ids |
|
||||
item_filter = eval(record.item_filter) if record.item_filter else [] |
|
||||
formatted_file_content = self.generate_formatted_file_content( |
|
||||
column_ids, item_filter, record) |
|
||||
csv_content = StringIO() |
|
||||
csv_writer = csv.writer(csv_content) |
|
||||
column_header = [column.name for column in column_ids] |
|
||||
csv_writer.writerow(column_header) |
|
||||
for row in formatted_file_content: |
|
||||
csv_writer.writerow(row) |
|
||||
# Get CSV content as a string |
|
||||
csv_string = csv_content.getvalue() |
|
||||
csv_content.close() |
|
||||
headers = [ |
|
||||
('Content-Type', 'text/csv'), |
|
||||
('Content-Disposition', http.content_disposition(name + '.csv')), |
|
||||
] |
|
||||
return request.make_response(csv_string, headers=headers) |
|
@ -1,6 +0,0 @@ |
|||||
## Module <odoo_fb_insta_product_data_feed> |
|
||||
|
|
||||
#### 20.04.2024 |
|
||||
#### Version 17.0.1.0.0 |
|
||||
#### ADD |
|
||||
- Initial Commit for Product Data Feed Generation |
|
@ -1,24 +0,0 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
############################################################################### |
|
||||
# |
|
||||
# Cybrosys Technologies Pvt. Ltd. |
|
||||
# |
|
||||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|
||||
# Author: Subina P (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 field_column_value |
|
||||
from . import product_data_feed |
|
||||
from . import product_data_feed_columns |
|
@ -1,40 +0,0 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
############################################################################### |
|
||||
# |
|
||||
# Cybrosys Technologies Pvt. Ltd. |
|
||||
# |
|
||||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|
||||
# Author: Subina P (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 FieldColumnValue(models.Model): |
|
||||
"""Model for storing field column values. |
|
||||
|
|
||||
This class represents field column values used in a product data feed. |
|
||||
It is used to define the mapping of column names to their corresponding |
|
||||
values. |
|
||||
""" |
|
||||
_name = 'field.column.value' |
|
||||
_description = 'Field Column Value' |
|
||||
_rec_name = 'value' |
|
||||
|
|
||||
feed_id = fields.Many2one('product.data.feed', |
|
||||
string='Feed Name', help='Feed Name') |
|
||||
column_name = fields.Char(string='Column Name', |
|
||||
help='Enter the column name.') |
|
||||
value = fields.Char(string='Value', help='Value of the column name.') |
|
@ -1,246 +0,0 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
############################################################################### |
|
||||
# |
|
||||
# Cybrosys Technologies Pvt. Ltd. |
|
||||
# |
|
||||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|
||||
# Author: Subina P (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 base64 |
|
||||
import secrets |
|
||||
import string |
|
||||
import csv |
|
||||
from io import StringIO |
|
||||
from odoo import api, fields, models |
|
||||
|
|
||||
|
|
||||
class ProductDataFeed(models.Model): |
|
||||
"""Data feed model for managing and generating product data feeds. |
|
||||
This class represents a product data feed, which can be used to export |
|
||||
product information in a specific format. It inherits from 'mail.thread' |
|
||||
and 'mail.activity.mixin' to provide messaging and activity tracking |
|
||||
capabilities.""" |
|
||||
_name = 'product.data.feed' |
|
||||
_description = 'Product Data Feed' |
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin'] |
|
||||
|
|
||||
name = fields.Char(string='Name', help='Name of the feed', copy=False, |
|
||||
required=True) |
|
||||
url_link = fields.Char(string='Link', help='Data feed download link', |
|
||||
compute='_compute_url_link') |
|
||||
is_token = fields.Boolean(string='Use Token', |
|
||||
help='Use token or Not for the ' |
|
||||
'security') |
|
||||
access_token = fields.Char(string='Access Token', |
|
||||
help='Access Token of the feed', |
|
||||
compute='_compute_access_token') |
|
||||
website_id = fields.Many2one('website', string='Websites', |
|
||||
help='Allow this data feed for the selected ' |
|
||||
'websites.Allow for all if not set ') |
|
||||
format = fields.Char(string='File Formate', |
|
||||
help='The file formate of the data feed.', |
|
||||
default='CSV', readonly=True) |
|
||||
is_file_name = fields.Boolean(string='File Name', |
|
||||
help='Enabled the file name') |
|
||||
name_show = fields.Char(string='File Name', help='Show the file name', |
|
||||
compute='_compute_name_show') |
|
||||
use_model = fields.Selection( |
|
||||
[('Product', 'Product'), ('Product Variant', 'Product Variant')], |
|
||||
string='Use Model', help='Used model of the product feed', |
|
||||
default='Product', required=True) |
|
||||
used_model = fields.Char(string='Used Model', help='Model') |
|
||||
item_filter = fields.Char(string='Item Filter', help='The model domain to' |
|
||||
' filter for the feed') |
|
||||
feed_columns_line_ids = fields.One2many('product.data.feed.columns', |
|
||||
'data_feed_columns_id', |
|
||||
string='Columns', |
|
||||
help='Feed column line', |
|
||||
readonly=True,) |
|
||||
columns_count = fields.Integer(string='Columns Count', |
|
||||
help='Total number of columns used this ' |
|
||||
'feed', |
|
||||
compute='_compute_columns_count') |
|
||||
|
|
||||
def generate_formatted_file_content(self, columns, item_filter): |
|
||||
"""Generate formatted content for a file based on specified columns |
|
||||
and an item filter.This method applies the provided filter criteria to |
|
||||
fetch relevant items from the environment, and then generates formatted |
|
||||
rows of values for the specified columns for each item.""" |
|
||||
# Apply the filter criteria and fetch the relevant items |
|
||||
filtered_items = self.env[self.used_model].search(item_filter) |
|
||||
formatted_rows = [] |
|
||||
# Iterate over each item and generate a row of values |
|
||||
for item in filtered_items: |
|
||||
row = [] |
|
||||
value = '' |
|
||||
for column in columns: |
|
||||
if column.type == 'Model Field': |
|
||||
# Access the field value directly |
|
||||
model_value = getattr(item, column.value_id.name, '') |
|
||||
if model_value: |
|
||||
value = model_value |
|
||||
else: |
|
||||
value = '' |
|
||||
|
|
||||
elif column.type == 'Special': |
|
||||
if column.special_type == 'product_availability': |
|
||||
# Access the product's on-hand quantity |
|
||||
on_hand_qty = item.qty_available |
|
||||
# Set value based on on-hand quantity |
|
||||
if on_hand_qty == 0: |
|
||||
value = 'out of stock' |
|
||||
else: |
|
||||
value = 'in stock' |
|
||||
elif column.special_type == 'qty': |
|
||||
value = item.qty_available |
|
||||
elif column.special_type == 'product_price': |
|
||||
value = item.standard_price |
|
||||
elif column.special_type == 'disc_price': |
|
||||
value = item.list_price |
|
||||
elif column.special_type == 'price_without_tax': |
|
||||
value = item.list_price |
|
||||
elif column.special_type == 'price_currency': |
|
||||
value = self.currency_id.name |
|
||||
elif column.special_type == 'image_link': |
|
||||
value = item.image_1920 |
|
||||
elif column.special_type == 'price_tax': |
|
||||
if item.taxes_id: |
|
||||
value = (item.list_price * ( |
|
||||
item.taxes_id.amount / 100) + |
|
||||
item.list_price) |
|
||||
else: |
|
||||
value = 0.0 |
|
||||
elif column.type == 'Text': |
|
||||
value = column.value |
|
||||
elif column.type == 'Value': |
|
||||
value = column.field_value_id.value |
|
||||
else: |
|
||||
value = column.value |
|
||||
if value: |
|
||||
row.append(value) |
|
||||
formatted_rows.append(row) |
|
||||
return formatted_rows |
|
||||
|
|
||||
def action_download_doc(self): |
|
||||
"""Download the catalog""" |
|
||||
columns = self.feed_columns_line_ids |
|
||||
item_filter = eval(self.item_filter) if self.item_filter else [] |
|
||||
formatted_file_content = self.generate_formatted_file_content( |
|
||||
columns, item_filter) |
|
||||
# Create a CSV content string |
|
||||
csv_content = StringIO() |
|
||||
csv_writer = csv.writer(csv_content) |
|
||||
column_header = [column.name for column in columns] |
|
||||
csv_writer.writerow(column_header) |
|
||||
for row in formatted_file_content: |
|
||||
csv_writer.writerow(row) |
|
||||
encoded_content = csv_content.getvalue().encode('utf-8') |
|
||||
# Close the StringIO buffer |
|
||||
csv_content.close() |
|
||||
attachment = self.env['ir.attachment'].create({ |
|
||||
'name': self.name_show if self.name_show else 'feed', |
|
||||
'type': 'binary', |
|
||||
'datas': base64.b64encode(encoded_content), |
|
||||
'res_model': self.used_model, |
|
||||
'res_id': self.id, |
|
||||
'mimetype': 'text/csv' |
|
||||
}) |
|
||||
return { |
|
||||
'type': 'ir.actions.act_url', |
|
||||
'target': 'new', |
|
||||
'url': f"/web/content/{attachment.id}?download=true" |
|
||||
} |
|
||||
|
|
||||
def action_product_items(self): |
|
||||
"""Open the product item list""" |
|
||||
return { |
|
||||
'type': 'ir.actions.act_window', |
|
||||
'name': 'Feed Items', |
|
||||
'view_mode': 'tree,form', |
|
||||
'res_model': self.used_model, |
|
||||
'domain': self.item_filter, |
|
||||
'context': self.env.context, |
|
||||
} |
|
||||
|
|
||||
def action_columns_creation(self): |
|
||||
"""Create the columns for feed.""" |
|
||||
return { |
|
||||
'type': 'ir.actions.act_window', |
|
||||
'name': 'Columns', |
|
||||
'view_mode': 'tree,form', |
|
||||
'res_model': 'product.data.feed.columns', |
|
||||
'context': { |
|
||||
'default_feed_id': self.id, |
|
||||
'default_data_feed_columns_id': self.id, |
|
||||
}, |
|
||||
'domain': [('feed_id', '=', self.id)] |
|
||||
} |
|
||||
|
|
||||
@api.depends('access_token') |
|
||||
def _compute_access_token(self): |
|
||||
"""Update the access token when enabling the token boolean field""" |
|
||||
access_tokens = secrets.token_urlsafe(27) |
|
||||
self.write({'access_token': access_tokens}) |
|
||||
|
|
||||
def action_refresh_token(self): |
|
||||
"""Refresh and generate new token""" |
|
||||
access_tokens = secrets.token_urlsafe( |
|
||||
27) # 27 bytes gives you 36 characters |
|
||||
self.write({'access_token': access_tokens}) |
|
||||
|
|
||||
@api.depends('name_show') |
|
||||
def _compute_name_show(self): |
|
||||
"""Generate the random name when enabling the file_name""" |
|
||||
prefix = "feed-" |
|
||||
random_length = 4 |
|
||||
random_chars = ''.join( |
|
||||
secrets.choice(string.ascii_letters + string.digits) for _ in |
|
||||
range(random_length)) |
|
||||
random_name = prefix + random_chars |
|
||||
self.write({'name_show': random_name}) |
|
||||
|
|
||||
@api.onchange('use_model') |
|
||||
def _onchange_use_model(self): |
|
||||
"""When changing the use_model it update the model into used_model""" |
|
||||
if self.use_model == 'Product': |
|
||||
self.write({'used_model': 'product.template'}) |
|
||||
else: |
|
||||
self.write({'used_model': 'product.product'}) |
|
||||
|
|
||||
@api.depends('format', 'name_show', 'is_token') |
|
||||
def _compute_url_link(self): |
|
||||
"""Compute the downloading link""" |
|
||||
for feed in self: |
|
||||
base_url = self.env['ir.config_parameter'].get_param( |
|
||||
'web.base.url') + '/product_data' |
|
||||
if feed.is_token and feed.is_file_name: |
|
||||
feed.url_link = f'{base_url}/{self.id}/{feed.name_show}.{feed.format}?access_token={feed.access_token}' |
|
||||
elif feed.is_file_name: |
|
||||
feed.url_link = f'{base_url}/{self.id}/{feed.name_show}.{feed.format}' |
|
||||
elif feed.is_token: |
|
||||
feed.url_link = f'{base_url}/{self.id}/feed.{feed.format}?access_token={feed.access_token}' |
|
||||
else: |
|
||||
feed.url_link = f'{base_url}/{self.id}/feed.{feed.format}' |
|
||||
|
|
||||
def _compute_columns_count(self): |
|
||||
"""Calculate the total number of column count of the current feed""" |
|
||||
for rec in self: |
|
||||
if rec.ids: |
|
||||
rec.columns_count = self.env[ |
|
||||
'product.data.feed.columns'].search_count( |
|
||||
[('feed_id', '=', rec.id)]) |
|
||||
else: |
|
||||
rec.columns_count = 0 |
|
@ -1,60 +0,0 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
############################################################################### |
|
||||
# |
|
||||
# Cybrosys Technologies Pvt. Ltd. |
|
||||
# |
|
||||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|
||||
# Author: Subina P (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 ProductDataFeedColumns(models.Model): |
|
||||
"""Model for defining columns in a product data feed. |
|
||||
|
|
||||
This class represents the columns used in a product data feed. These columns |
|
||||
define the structure of the data to be included in the feed, including |
|
||||
various types such as text, model fields, values, and special types.""" |
|
||||
_name = 'product.data.feed.columns' |
|
||||
_description = 'Product Data Feed Columns' |
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin'] |
|
||||
|
|
||||
name = fields.Char(string='Name', help='Columns name') |
|
||||
feed_id = fields.Many2one('product.data.feed', |
|
||||
string='Feed', help='Feed Name') |
|
||||
type = fields.Selection( |
|
||||
[('Text', 'Text'), ('Model Field', 'Model Field'), |
|
||||
('Value', 'Value'), ('Special', 'Special')], |
|
||||
string='Type', help='Choose the type of the columns') |
|
||||
value = fields.Char(string="Value", help='Enter the column value') |
|
||||
value_id = fields.Many2one('ir.model.fields', |
|
||||
string="Value", help='Choose the column value', |
|
||||
) |
|
||||
field_value_id = fields.Many2one('field.column.value', |
|
||||
string="Value", |
|
||||
help='Choose the column value') |
|
||||
data_feed_columns_id = fields.Many2one('product.data.feed', |
|
||||
string='Data Columns', |
|
||||
help='Data columns inverse field') |
|
||||
special_type = fields.Selection( |
|
||||
[('product_price', 'Product Price'), |
|
||||
('disc_price', 'Discounted Price'), |
|
||||
('price_currency', 'Price Currency'), |
|
||||
('product_availability', 'Product Availability'), |
|
||||
('qty', 'Qty in Stock'), |
|
||||
('price_tax', 'Product Price(with Taxes)'), |
|
||||
('price_without_tax', 'Product Price(without Taxes)')], |
|
||||
string='Special Type', help='Choose the special type') |
|
|
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 310 B |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 576 B |
Before Width: | Height: | Size: 733 B |
Before Width: | Height: | Size: 911 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 673 B |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 878 B |
Before Width: | Height: | Size: 653 B |
Before Width: | Height: | Size: 905 B |
Before Width: | Height: | Size: 839 B |
Before Width: | Height: | Size: 427 B |
Before Width: | Height: | Size: 627 B |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 988 B |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 589 B |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 565 B |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 967 B |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 284 KiB |
Before Width: | Height: | Size: 118 KiB |
Before Width: | Height: | Size: 108 KiB |
Before Width: | Height: | Size: 87 KiB |
Before Width: | Height: | Size: 72 KiB |
Before Width: | Height: | Size: 92 KiB |
Before Width: | Height: | Size: 85 KiB |
Before Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 76 KiB |
Before Width: | Height: | Size: 180 KiB |
Before Width: | Height: | Size: 77 KiB |
Before Width: | Height: | Size: 85 KiB |
Before Width: | Height: | Size: 116 KiB |
Before Width: | Height: | Size: 91 KiB |
Before Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 167 KiB |
Before Width: | Height: | Size: 66 KiB |
Before Width: | Height: | Size: 162 KiB |
Before Width: | Height: | Size: 161 KiB |
Before Width: | Height: | Size: 161 KiB |
Before Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 95 KiB |
Before Width: | Height: | Size: 156 KiB |
Before Width: | Height: | Size: 197 KiB |
Before Width: | Height: | Size: 161 KiB |
Before Width: | Height: | Size: 474 KiB |
Before Width: | Height: | Size: 81 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 173 KiB |
Before Width: | Height: | Size: 87 KiB |
Before Width: | Height: | Size: 9.8 KiB |
@ -1,19 +0,0 @@ |
|||||
<?xml version="1.0" encoding="UTF-8" ?> |
|
||||
<odoo> |
|
||||
<!-- Values creation form--> |
|
||||
<record id="field_column_value_view_form" model="ir.ui.view"> |
|
||||
<field name="name">field.column.value.view.form</field> |
|
||||
<field name="model">field.column.value</field> |
|
||||
<field name="arch" type="xml"> |
|
||||
<form> |
|
||||
<sheet> |
|
||||
<group> |
|
||||
<field name="feed_id"/> |
|
||||
<field name="column_name"/> |
|
||||
<field name="value"/> |
|
||||
</group> |
|
||||
</sheet> |
|
||||
</form> |
|
||||
</field> |
|
||||
</record> |
|
||||
</odoo> |
|
@ -1,49 +0,0 @@ |
|||||
<?xml version="1.0" encoding="UTF-8" ?> |
|
||||
<odoo> |
|
||||
<!-- Product data feed columns form view--> |
|
||||
<record id="product_data_feed_columns_view_form" model="ir.ui.view"> |
|
||||
<field name="name">product.data.feed.columns.view.form</field> |
|
||||
<field name="model">product.data.feed.columns</field> |
|
||||
<field name="arch" type="xml"> |
|
||||
<form name="product_data_feed_columns"> |
|
||||
<sheet> |
|
||||
<label for="name"/> |
|
||||
<div class="oe_title"> |
|
||||
<h3> |
|
||||
<field name="name" required="1"/> |
|
||||
</h3> |
|
||||
</div> |
|
||||
<group name="main"> |
|
||||
<group> |
|
||||
<field name="feed_id" default="context.get('default_feed_id')"/> |
|
||||
<field name="type"/> |
|
||||
<field name="value" invisible="type != 'Text'"/> |
|
||||
<field name="value_id" invisible="type != 'Model Field'"/> |
|
||||
<field name="field_value_id" invisible="type != 'Value'" context="{'default_feed_id': feed_id, 'default_column_name': name, 'default_value': field_value_id}"/> |
|
||||
<field name="special_type" invisible="type != 'Special'"/> |
|
||||
<field name="data_feed_columns_id" invisible="1" default="context.get('default_data_feed_columns_id')"/> |
|
||||
</group> |
|
||||
</group> |
|
||||
</sheet> |
|
||||
<div class="oe_chatter"> |
|
||||
<field name="message_follower_ids"/> |
|
||||
<field name="activity_ids"/> |
|
||||
<field name="message_ids"/> |
|
||||
</div> |
|
||||
</form> |
|
||||
</field> |
|
||||
</record> |
|
||||
<!-- Product data feed column tree view--> |
|
||||
<record id="product_data_feed_columns_view_tree" model="ir.ui.view"> |
|
||||
<field name="name">product.data.feed.columns.view.tree</field> |
|
||||
<field name="model">product.data.feed.columns</field> |
|
||||
<field name="arch" type="xml"> |
|
||||
<tree> |
|
||||
<field name="name"/> |
|
||||
<field name="type"/> |
|
||||
<field name="value" string="Text Value"/> |
|
||||
<field name="field_value_id"/> |
|
||||
</tree> |
|
||||
</field> |
|
||||
</record> |
|
||||
</odoo> |
|
@ -1,111 +0,0 @@ |
|||||
<?xml version="1.0" encoding="UTF-8" ?> |
|
||||
<odoo> |
|
||||
<!-- product data feed action--> |
|
||||
<record id="product_data_feed_action" model="ir.actions.act_window"> |
|
||||
<field name="name">Data Feed</field> |
|
||||
<field name="type">ir.actions.act_window</field> |
|
||||
<field name="res_model">product.data.feed</field> |
|
||||
<field name="view_mode">tree,form</field> |
|
||||
<field name="help" type="html"> |
|
||||
<p class="oe_view_nocontent_create"> |
|
||||
Click to add the data feed details. |
|
||||
</p> |
|
||||
</field> |
|
||||
</record> |
|
||||
<!-- Product data feed form view--> |
|
||||
<record id="product_data_feed_view_form" model="ir.ui.view"> |
|
||||
<field name="name">product.data.feed.view.form</field> |
|
||||
<field name="model">product.data.feed</field> |
|
||||
<field name="arch" type="xml"> |
|
||||
<form name="product_data_feed"> |
|
||||
<header> |
|
||||
<button name="action_download_doc" type="object" |
|
||||
string="Download" class="btn-secondary" |
|
||||
invisible="feed_columns_line_ids == []" |
|
||||
widget="statusbar"/> |
|
||||
</header> |
|
||||
<sheet name="product_data_feed"> |
|
||||
<!--smart button action--> |
|
||||
<div name="button_box" class="oe_button_box"> |
|
||||
<button name="action_product_items" string="Items" |
|
||||
class="oe_stat_button" |
|
||||
icon="fa-cubes" type="object"/> |
|
||||
<button name="action_columns_creation" type="object" |
|
||||
class="oe_stat_button" string="Columns" |
|
||||
icon="fa-list"> |
|
||||
<field name="columns_count" readonly="True"/> |
|
||||
<span class="o_stat_text">Columns</span> |
|
||||
</button> |
|
||||
</div> |
|
||||
<div class="oe_title"> |
|
||||
<h1> |
|
||||
<field name="name" required="1" |
|
||||
placeholder="Feed Name...."/> |
|
||||
</h1> |
|
||||
</div> |
|
||||
<field name="url_link" |
|
||||
widget="CopyClipboardChar" |
|
||||
class="w-100 pb-2"/> |
|
||||
<group> |
|
||||
<group> |
|
||||
<field name="is_token" widget="boolean_toggle"/> |
|
||||
<label for="access_token" invisible="is_token == False"/> |
|
||||
<div class="o_row" invisible="is_token == False"> |
|
||||
<field name="access_token"/> |
|
||||
<button class="btn-secondary" name="action_refresh_token" icon="fa-refresh" type="object" title="Refresh Token"/> |
|
||||
</div> |
|
||||
<field name="website_id"/> |
|
||||
<label for="name_show"/> |
|
||||
<div class="o_row"> |
|
||||
<field name="is_file_name" widget="boolean_toggle"/> |
|
||||
<field name="name_show" invisible="is_file_name == False" nolabel="1"/> |
|
||||
</div> |
|
||||
</group> |
|
||||
<group> |
|
||||
<field name="use_model" widget="radio"/> |
|
||||
<field name="used_model" invisible="1"/> |
|
||||
<field name="item_filter" widget="domain" options="{'model': 'product.template', 'in_dialog': true}" |
|
||||
invisible="use_model != 'Product'"/> |
|
||||
<field name="item_filter" widget="domain" options="{'model': 'product.product', 'in_dialog': true}" |
|
||||
invisible="use_model != 'Product Variant'"/> |
|
||||
<field name="format"/> |
|
||||
</group> |
|
||||
<notebook> |
|
||||
<page string="Columns" name="Columns"> |
|
||||
<field name="feed_columns_line_ids" readonly="1"> |
|
||||
<tree> |
|
||||
<field name="name"/> |
|
||||
</tree> |
|
||||
</field> |
|
||||
</page> |
|
||||
</notebook> |
|
||||
</group> |
|
||||
</sheet> |
|
||||
<div class="oe_chatter"> |
|
||||
<field name="message_follower_ids"/> |
|
||||
<field name="activity_ids"/> |
|
||||
<field name="message_ids"/> |
|
||||
</div> |
|
||||
</form> |
|
||||
</field> |
|
||||
</record> |
|
||||
<!-- Product data feed tree view--> |
|
||||
<record id="product_data_feed_view_tree" model="ir.ui.view"> |
|
||||
<field name="name">product.data.feed.view.tree</field> |
|
||||
<field name="model">product.data.feed</field> |
|
||||
<field name="arch" type="xml"> |
|
||||
<tree> |
|
||||
<field name="name"/> |
|
||||
<field name="used_model"/> |
|
||||
<field name="is_token"/> |
|
||||
<field name="columns_count"/> |
|
||||
</tree> |
|
||||
</field> |
|
||||
</record> |
|
||||
<!-- product data feed menu--> |
|
||||
<menuitem id="product_data_feed_menu" |
|
||||
name="Product Data Feed" |
|
||||
parent="website_sale.menu_catalog" |
|
||||
action="product_data_feed_action" |
|
||||
sequence="6"/> |
|
||||
</odoo> |
|