| @ -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> | |||