| @ -0,0 +1,41 @@ | |||
| .. image:: https://img.shields.io/badge/licence-LGPL--3-green.svg | |||
|     :target: https://www.gnu.org/licenses/lgpl-3.0-standalone.html | |||
|     :alt: License: LGPL-3 | |||
| 
 | |||
| Auto Database Backup | |||
| ==================== | |||
| * Generate Database Backups and store to multiple locations | |||
| 
 | |||
| License | |||
| ======= | |||
| General Public License, Version 3 (LGPL v3). | |||
| (https://www.gnu.org/licenses/lgpl-3.0-standalone.html) | |||
| 
 | |||
| Company | |||
| ======= | |||
| * Cybrosys Techno Solutions <https://cybrosys.com/>__ | |||
| 
 | |||
| Credits | |||
| ======= | |||
| * Developer: (v12) Ajmunnisa @ Cybrosys , Contact : odoo@cybrosys.com | |||
| 
 | |||
| Contacts | |||
| ======== | |||
| * Mail Contact : odoo@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>`__ | |||
| @ -0,0 +1,22 @@ | |||
| # -*- coding: utf-8 -*- | |||
| ############################################################################# | |||
| # | |||
| #    Cybrosys Technologies Pvt. Ltd. | |||
| # | |||
| #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | |||
| #    Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) | |||
| # | |||
| #    You can modify it under the terms of the GNU LESSER | |||
| #    GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | |||
| # | |||
| #    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | |||
| #    (LGPL v3) along with this program. | |||
| #    If not, see <http://www.gnu.org/licenses/>. | |||
| # | |||
| ############################################################################# | |||
| from . import models | |||
| @ -0,0 +1,49 @@ | |||
| # -*- coding: utf-8 -*- | |||
| ############################################################################# | |||
| # | |||
| #    Cybrosys Technologies Pvt. Ltd. | |||
| # | |||
| #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | |||
| #    Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) | |||
| # | |||
| #    You can modify it under the terms of the GNU LESSER | |||
| #    GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | |||
| # | |||
| #    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | |||
| #    (LGPL v3) along with this program. | |||
| #    If not, see <http://www.gnu.org/licenses/>. | |||
| # | |||
| ############################################################################# | |||
| { | |||
|     'name': "Auto Database Backup", | |||
|     'version': '12.0.1.0.0', | |||
|     'category': 'Extra Tools', | |||
|     'summary': 'Generate automatic backup of databases and store to local, ' | |||
|                'google drive, dropbox, nextcloud, amazon S3, onedrive or ' | |||
|                'remote server', | |||
|     'description': 'This module has been developed for creating database ' | |||
|                    'backups automatically and store it to the different ' | |||
|                    'locations,database backup, backup, Google Drive, Dropbox, ' | |||
|                    'Onedrive, Nextcloud, Amazon S3, automatic backup', | |||
|     'author': "Cybrosys Techno Solutions", | |||
|     'company': 'Cybrosys Techno Solutions', | |||
|     'maintainer': 'Cybrosys Techno Solutions', | |||
|     'website': "https://www.cybrosys.com", | |||
|     'depends': ['mail', 'google_drive'], | |||
|     'data': [ | |||
|         'security/ir.model.access.csv', | |||
|         'data/ir_cron_data.xml', | |||
|         'data/mail_template_data.xml', | |||
|         'views/db_backup_configure_views.xml' | |||
|     ], | |||
|     'images': ['static/description/banner.jpg'], | |||
|     'license': 'LGPL-3', | |||
|     'installable': True, | |||
|     'auto_install': False, | |||
|     'application': False, | |||
| } | |||
| @ -0,0 +1,16 @@ | |||
| <?xml version="1.0" encoding="utf-8" ?> | |||
| <odoo> | |||
|     <data noupdate="1"> | |||
|         <!-- Schedule action for generating automatic database backup--> | |||
|         <record id="ir_cron_auto_db_backup" model="ir.cron"> | |||
|             <field name="name">Backup : Automatic Database Backup</field> | |||
|             <field name="model_id" ref="model_db_backup_configure"/> | |||
|             <field name="state">code</field> | |||
|             <field name="code">model._schedule_auto_backup()</field> | |||
|             <field name="interval_number">1</field> | |||
|             <field name="interval_type">days</field> | |||
|             <field name="numbercall">-1</field> | |||
|             <field name="active">False</field> | |||
|         </record> | |||
|     </data> | |||
| </odoo> | |||
| @ -0,0 +1,126 @@ | |||
| <?xml version="1.0" encoding="utf-8" ?> | |||
| <odoo> | |||
|     <data noupdate="1"> | |||
|         <!--        Database backup operation Successful email template--> | |||
|         <!--        Database backup operation Successful email template--> | |||
|         <record id="mail_template_data_db_backup_successful" | |||
|                 model="mail.template"> | |||
|             <field name="name">Database Backup: Notification Successful</field> | |||
|             <field name="model_id" | |||
|                    ref="auto_database_backup.model_db_backup_configure"/> | |||
|             <field name="subject">Database Backup Successful: | |||
|                 ${object.db_name} | |||
|             </field> | |||
|             <field name="email_to">${object.user_id.email_formatted | safe} | |||
|             </field> | |||
|             <field name="body_html" type="xml"> | |||
|                 <p style="margin: 0px;"> | |||
|                     <span>Dear ${object.user_id.sudo().name}, | |||
|                     </span> | |||
|                     <br/> | |||
|                     <br/> | |||
|                     <span style="margin-top: 8px;">Backup of the database <i> | |||
|                         ${object.db_name} | |||
|                     </i> has been successfully | |||
|                         generated and stored to | |||
|                         % if object.backup_destination in ('local'): | |||
|                         <i>Local</i> | |||
|                         % elif object.backup_destination in ('google_drive'): | |||
|                         <i>Google Drive</i> | |||
|                         % elif object.backup_destination in ('ftp'): | |||
|                         <i>FTP Server</i> | |||
|                         % elif object.backup_destination in ('sftp'): | |||
|                         <i>SFTP Server</i> | |||
|                         % endif | |||
|                         . | |||
|                         <br/> | |||
|                         <br/> | |||
|                         Database Name: ${object.db_name} | |||
|                         <br/> | |||
|                         Destination: | |||
|                         % if object.backup_destination in ('local'): | |||
|                         <i>Local</i> | |||
|                         % elif object.backup_destination in ('google_drive'): | |||
|                         <i>Google Drive</i> | |||
|                         % elif object.backup_destination in ('ftp'): | |||
|                         <i>FTP Server</i> | |||
|                         % elif object.backup_destination in ('sftp'): | |||
|                         <i>SFTP Server</i> | |||
|                         % endif | |||
|                         % if object.backup_destination in ('local', 'ftp', | |||
|                         'sftp') | |||
|                         <br/> | |||
|                         Backup Path: | |||
|                         % if object.backup_destination in ('local'): | |||
|                         ${object.backup_path} | |||
|                         % elif object.backup_destination in ('ftp'): | |||
|                         ${object.ftp_path} | |||
|                         % elif object.backup_destination in ('sftp'): | |||
|                         ${object.sftp_path} | |||
|                         % endif | |||
|                         % endif | |||
|                         <br/> | |||
|                         Backup Type: ${object.backup_format} | |||
|                         <br/> | |||
|                         Backup FileName: ${object.backup_filename} | |||
|                     </span> | |||
|                 </p> | |||
|             </field> | |||
|         </record> | |||
|         <!--            Database backup operation failed email templated--> | |||
|         <record id="mail_template_data_db_backup_failed" model="mail.template"> | |||
|             <field name="name">Database Backup: Notification Failed</field> | |||
|             <field name="model_id" | |||
|                    ref="auto_database_backup.model_db_backup_configure"/> | |||
|             <field name="subject">Database Backup Failed: ${object.db_name} | |||
|             </field> | |||
|             <field name="email_to">${object.user_id.email_formatted | safe} | |||
|             </field> | |||
|             <field name="body_html" type="xml"> | |||
|                 <p style="margin: 0px;"> | |||
|                     <span>Dear ${object.user_id.sudo().name}, | |||
|                     </span> | |||
|                     <br/> | |||
|                     <br/> | |||
|                     <span style="margin-top: 8px;">Backup generation of the | |||
|                         database <i>${object.db_name}</i> has been | |||
|                         Failed. | |||
|                         <br/> | |||
|                         <br/> | |||
|                         Database Name: ${object.db_name} | |||
|                         <br/> | |||
|                         Destination: | |||
|                         % if object.backup_destination in ('local'): | |||
|                         <i>Local</i> | |||
|                         % elif object.backup_destination in ('google_drive'): | |||
|                         <i>Google Drive</i> | |||
|                         % elif object.backup_destination in ('ftp'): | |||
|                         <i>FTP Server</i> | |||
|                         % elif object.backup_destination in ('sftp'): | |||
|                         <i>SFTP Server</i> | |||
|                         % endif | |||
|                         % if object.backup_destination in ('local', 'ftp', | |||
|                         'sftp') | |||
|                         <br/> | |||
|                         Backup Path: | |||
|                         % if object.backup_destination in ('local'): | |||
|                         ${object.backup_path} | |||
|                         % elif object.backup_destination in ('ftp'): | |||
|                         ${object.ftp_path} | |||
|                         % elif object.backup_destination in ('sftp'): | |||
|                         ${object.sftp_path} | |||
|                         % endif | |||
|                         % endif | |||
|                         <br/> | |||
|                         Backup Type: ${object.backup_format} | |||
|                         <br/> | |||
|                         <br/> | |||
|                         <b>Error Message:</b> | |||
|                         <br/> | |||
|                         <i>${object.generated_exception}</i> | |||
|                     </span> | |||
|                 </p> | |||
|             </field> | |||
|         </record> | |||
|     </data> | |||
| </odoo> | |||
| @ -0,0 +1,6 @@ | |||
| ## Module <auto_database_backup> | |||
| 
 | |||
| #### 12.02.2024 | |||
| #### Version 12.0.1.0.0 | |||
| #### ADD | |||
| - Initial commit for Auto Database Backup | |||
| @ -0,0 +1,22 @@ | |||
| # -*- coding: utf-8 -*- | |||
| ############################################################################# | |||
| # | |||
| #    Cybrosys Technologies Pvt. Ltd. | |||
| # | |||
| #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | |||
| #    Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) | |||
| # | |||
| #    You can modify it under the terms of the GNU LESSER | |||
| #    GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | |||
| # | |||
| #    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | |||
| #    (LGPL v3) along with this program. | |||
| #    If not, see <http://www.gnu.org/licenses/>. | |||
| # | |||
| ############################################################################# | |||
| from . import db_backup_configure | |||
| @ -0,0 +1,328 @@ | |||
| # -*- coding: utf-8 -*- | |||
| ############################################################################# | |||
| # | |||
| #    Cybrosys Technologies Pvt. Ltd. | |||
| # | |||
| #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | |||
| #    Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) | |||
| # | |||
| #    You can modify it under the terms of the GNU LESSER | |||
| #    GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | |||
| # | |||
| #    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | |||
| #    (LGPL v3) along with this program. | |||
| #    If not, see <http://www.gnu.org/licenses/>. | |||
| # | |||
| ############################################################################# | |||
| import datetime | |||
| import errno | |||
| import ftplib | |||
| import json | |||
| import logging | |||
| import os | |||
| import odoo | |||
| import paramiko | |||
| import requests | |||
| import tempfile | |||
| from odoo import api, fields, models, _ | |||
| from odoo.exceptions import UserError, ValidationError | |||
| from odoo.service import db | |||
| 
 | |||
| _logger = logging.getLogger(__name__) | |||
| 
 | |||
| 
 | |||
| class DbBackupConfigure(models.Model): | |||
|     """Model for database backup configuration and backup functions""" | |||
|     _name = 'db.backup.configure' | |||
|     _description = 'Db Backup Configure' | |||
| 
 | |||
|     name = fields.Char(string='Name', required=True, | |||
|                        help='Name of the backup configuration') | |||
|     db_name = fields.Char(string='Database Name', required=True, | |||
|                           help='Name of the database') | |||
|     master_pwd = fields.Char(string='Master Password', required=True, | |||
|                              help='Master password of the database') | |||
|     backup_format = fields.Selection([ | |||
|         ('zip', 'Zip'), | |||
|         ('dump', 'Dump') | |||
|     ], string='Backup Format', default='zip', required=True, | |||
|         help='Backup Format') | |||
|     backup_destination = fields.Selection([ | |||
|         ('local', 'Local Storage'), | |||
|         ('google_drive', 'Google Drive'), | |||
|         ('ftp', 'FTP'), | |||
|         ('sftp', 'SFTP') | |||
|     ], string='Backup Destination', | |||
|         help='Specify the location that the backup need to store') | |||
|     backup_path = fields.Char(string='Backup Path', | |||
|                               help='Local storage directory path') | |||
|     sftp_host = fields.Char(string='SFTP Host', help='SFTP Host Name') | |||
|     sftp_port = fields.Char(string='SFTP Port', default=22, help='SFTP Port') | |||
|     sftp_user = fields.Char(string='SFTP User', help='SFTP user name') | |||
|     sftp_password = fields.Char(string='SFTP Password', help='SFTP Password') | |||
|     sftp_path = fields.Char(string='SFTP Path', help='SFTP Path') | |||
|     ftp_host = fields.Char(string='FTP Host', help='FTP Host Name') | |||
|     ftp_port = fields.Char(string='FTP Port', default=21, help='FTP Port') | |||
|     ftp_user = fields.Char(string='FTP User', help='FTP User') | |||
|     ftp_password = fields.Char(string='FTP Password', help='FTP password') | |||
|     ftp_path = fields.Char(string='FTP Path', help='FTP Path') | |||
|     active = fields.Boolean(default=True, | |||
|                             help='To know the configuration is active') | |||
|     save_to_drive = fields.Boolean(help='To know that the backup need ' | |||
|                                         'to save in drive') | |||
|     auto_remove = fields.Boolean(string='Remove Old Backups', | |||
|                                  help='Remove old backup if the value is true') | |||
|     days_to_remove = fields.Integer(string='Remove After', | |||
|                                     help='Automatically delete stored backups ' | |||
|                                          'after this specified number of days') | |||
|     google_drive_folder = fields.Char(string='Drive Folder ID') | |||
|     notify_user = fields.Boolean(string='Notify User', | |||
|                                  help='Send an email notification to user ' | |||
|                                       'when the backup operation is successful' | |||
|                                       ' or failed') | |||
|     user_id = fields.Many2one('res.users', string='User') | |||
|     backup_filename = fields.Char(string='Backup Filename', | |||
|                                   help='For Storing generated backup filename') | |||
|     generated_exception = fields.Char(string='Exception', | |||
|                                       help='Exception Encountered while Backup ' | |||
|                                            'generation') | |||
| 
 | |||
|     @api.constrains('db_name', 'master_pwd') | |||
|     def _check_db_credentials(self): | |||
|         """Validate entered database name and master password""" | |||
|         database_list = db.list_dbs() | |||
|         if self.db_name not in database_list: | |||
|             raise ValidationError(_("Invalid Database Name!")) | |||
|         try: | |||
|             odoo.service.db.check_super(self.master_pwd) | |||
|         except Exception: | |||
|             raise ValidationError(_("Invalid Master Password!")) | |||
| 
 | |||
|     def test_connection(self): | |||
|         """Test the sftp and ftp connection using entered credentials""" | |||
|         if self.backup_destination == 'sftp': | |||
|             client = paramiko.SSHClient() | |||
|             client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) | |||
|             try: | |||
|                 client.connect(hostname=self.sftp_host, | |||
|                                username=self.sftp_user, | |||
|                                password=self.sftp_password, | |||
|                                port=self.sftp_port) | |||
|                 sftp = client.open_sftp() | |||
|                 sftp.close() | |||
|             except Exception as e: | |||
|                 raise UserError(_("SFTP Exception: %s", e)) | |||
|             finally: | |||
|                 client.close() | |||
|         elif self.backup_destination == 'ftp': | |||
|             try: | |||
|                 ftp_server = ftplib.FTP() | |||
|                 ftp_server.connect(self.ftp_host, int(self.ftp_port)) | |||
|                 ftp_server.login(self.ftp_user, self.ftp_password) | |||
|                 ftp_server.quit() | |||
|             except Exception as e: | |||
|                 raise UserError(_("FTP Exception: %s", e)) | |||
|         title = _("Connection Test Succeeded!") | |||
|         message = _("Everything seems properly set up!") | |||
|         return { | |||
|             'type': 'ir.actions.client', | |||
|             'tag': 'display_notification', | |||
|             'params': { | |||
|                 'title': title, | |||
|                 'message': message, | |||
|                 'sticky': False, | |||
|             } | |||
|         } | |||
| 
 | |||
|     def _schedule_auto_backup(self): | |||
|         """Function for generating and storing backup | |||
|         Database backup for all the active records in backup configuration | |||
|         model will be created""" | |||
|         records = self.search([]) | |||
|         mail_template_success = self.env.ref( | |||
|             'auto_database_backup.mail_template_data_db_backup_successful') | |||
|         mail_template_failed = self.env.ref( | |||
|             'auto_database_backup.mail_template_data_db_backup_failed') | |||
|         for rec in records: | |||
|             backup_time = datetime.datetime.utcnow().strftime( | |||
|                 "%Y-%m-%d_%H-%M-%S") | |||
|             backup_filename = "%s_%s.%s" % ( | |||
|                 rec.db_name, backup_time, rec.backup_format) | |||
|             rec.backup_filename = backup_filename | |||
|             # Local backup | |||
|             if rec.backup_destination == 'local': | |||
|                 try: | |||
|                     if not os.path.isdir(rec.backup_path): | |||
|                         os.makedirs(rec.backup_path) | |||
|                     backup_file = os.path.join(rec.backup_path, | |||
|                                                backup_filename) | |||
|                     file_open = open(backup_file, "wb") | |||
|                     odoo.service.db.dump_db(rec.db_name, file_open, | |||
|                                             rec.backup_format) | |||
|                     file_open.close() | |||
|                     # remove older backups | |||
|                     if rec.auto_remove: | |||
|                         for filename in os.listdir(rec.backup_path): | |||
|                             file = os.path.join(rec.backup_path, filename) | |||
|                             create_time = datetime.datetime.fromtimestamp( | |||
|                                 os.path.getctime(file)) | |||
|                             backup_duration = \ | |||
|                                 datetime.datetime.utcnow() - create_time | |||
|                             if backup_duration.days >= rec.days_to_remove: | |||
|                                 os.remove(file) | |||
|                     if rec.notify_user: | |||
|                         mail_template_success.send_mail(rec.id, | |||
|                                                         force_send=True) | |||
|                 except Exception as e: | |||
|                     rec.generated_exception = e | |||
|                     _logger.info('FTP Exception: %s', e) | |||
|                     if rec.notify_user: | |||
|                         mail_template_failed.send_mail(rec.id, force_send=True) | |||
|             # FTP backup | |||
|             elif rec.backup_destination == 'ftp': | |||
|                 try: | |||
|                     ftp_server = ftplib.FTP() | |||
|                     ftp_server.connect(rec.ftp_host, int(rec.ftp_port)) | |||
|                     ftp_server.login(rec.ftp_user, rec.ftp_password) | |||
|                     ftp_server.encoding = "utf-8" | |||
|                     temp = tempfile.NamedTemporaryFile( | |||
|                         suffix='.%s' % rec.backup_format) | |||
|                     try: | |||
|                         ftp_server.cwd(rec.ftp_path) | |||
|                     except ftplib.error_perm: | |||
|                         ftp_server.mkd(rec.ftp_path) | |||
|                         ftp_server.cwd(rec.ftp_path) | |||
|                     with open(temp.name, "wb+") as tmp: | |||
|                         odoo.service.db.dump_db(rec.db_name, tmp, | |||
|                                                 rec.backup_format) | |||
|                     ftp_server.storbinary('STOR %s' % backup_filename, | |||
|                                           open(temp.name, "rb")) | |||
|                     if rec.auto_remove: | |||
|                         files = ftp_server.nlst() | |||
|                         for file_open in files: | |||
|                             create_time = datetime.datetime.strptime( | |||
|                                 ftp_server. | |||
|                                 sendcmd( | |||
|                                     'MDTM ' + file_open)[4:], "%Y%m%d%H%M%S") | |||
|                             diff_days = ( | |||
|                                     datetime.datetime.now() - | |||
|                                     create_time).days | |||
|                             if diff_days >= rec.days_to_remove: | |||
|                                 ftp_server.delete(file_open) | |||
|                     ftp_server.quit() | |||
|                     if rec.notify_user: | |||
|                         mail_template_success.send_mail(rec.id, | |||
|                                                         force_send=True) | |||
|                 except Exception as e: | |||
|                     rec.generated_exception = e | |||
|                     _logger.info('FTP Exception: %s', e) | |||
|                     if rec.notify_user: | |||
|                         mail_template_failed.send_mail(rec.id, force_send=True) | |||
|             # SFTP backup | |||
|             elif rec.backup_destination == 'sftp': | |||
|                 client = paramiko.SSHClient() | |||
|                 client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) | |||
|                 try: | |||
|                     client.connect(hostname=rec.sftp_host, | |||
|                                    username=rec.sftp_user, | |||
|                                    password=rec.sftp_password, | |||
|                                    port=rec.sftp_port) | |||
|                     sftp = client.open_sftp() | |||
|                     temp = tempfile.NamedTemporaryFile( | |||
|                         suffix='.%s' % rec.backup_format) | |||
|                     with open(temp.name, "wb+") as tmp: | |||
|                         odoo.service.db.dump_db(rec.db_name, tmp, | |||
|                                                 rec.backup_format) | |||
|                     try: | |||
|                         sftp.chdir(rec.sftp_path) | |||
|                     except IOError as e: | |||
|                         if e.errno == errno.ENOENT: | |||
|                             sftp.mkdir(rec.sftp_path) | |||
|                             sftp.chdir(rec.sftp_path) | |||
|                     sftp.put(temp.name, backup_filename) | |||
|                     if rec.auto_remove: | |||
|                         files = sftp.listdir() | |||
|                         expired = list(filter(lambda fl: | |||
|                                               (datetime.datetime.now() - | |||
|                                                datetime.datetime.fromtimestamp( | |||
|                                                    sftp.stat(fl). | |||
|                                                    st_mtime)). | |||
|                                               days >= rec.days_to_remove, | |||
|                                               files)) | |||
|                         for file in expired: | |||
|                             sftp.unlink(file) | |||
|                     sftp.close() | |||
|                     if rec.notify_user: | |||
|                         mail_template_success.send_mail(rec.id, | |||
|                                                         force_send=True) | |||
|                 except Exception as e: | |||
|                     rec.generated_exception = e | |||
|                     _logger.info('SFTP Exception: %s', e) | |||
|                     if rec.notify_user: | |||
|                         mail_template_failed.send_mail(rec.id, force_send=True) | |||
|                 finally: | |||
|                     client.close() | |||
|             # Google Drive backup | |||
|             elif rec.backup_destination == 'google_drive': | |||
|                 temp = tempfile.NamedTemporaryFile( | |||
|                     suffix='.%s' % rec.backup_format) | |||
|                 with open(temp.name, "wb+") as tmp: | |||
|                     odoo.service.db.dump_db(rec.db_name, tmp, | |||
|                                             rec.backup_format) | |||
|                 try: | |||
|                     access_token = self.env[ | |||
|                         'google.drive.config'].sudo().get_access_token() | |||
|                     headers = {"Authorization": "Bearer %s" % access_token} | |||
|                     para = { | |||
|                         "name": backup_filename, | |||
|                         "parents": [rec.google_drive_folder], | |||
|                     } | |||
|                     files = { | |||
|                         'data': ('metadata', json.dumps(para), | |||
|                                  'application/json; charset=UTF-8'), | |||
|                         'file': open(temp.name, "rb") | |||
|                     } | |||
|                     requests.post( | |||
|                         "https://www.googleapis.com/upload/drive/v3/files?" | |||
|                         "uploadType=multipart", | |||
|                         headers=headers, | |||
|                         files=files) | |||
|                     if rec.auto_remove: | |||
|                         query = "parents = '%s'" % rec.google_drive_folder | |||
|                         files_req = requests.get( | |||
|                             "https://www.googleapis.com/drive/v3/files?q=%s" | |||
|                             % query, | |||
|                             headers=headers) | |||
|                         files = files_req.json()['files'] | |||
|                         for file in files: | |||
|                             file_date_req = requests.get( | |||
|                                 "https://www.googleapis.com/drive/v3/files/" | |||
|                                 "%s?fields=createdTime" % | |||
|                                 file['id'], | |||
|                                 headers=headers) | |||
|                             create_time = file_date_req.json()['createdTime'][ | |||
|                                           :19].replace('T', ' ') | |||
|                             diff_days = ( | |||
|                                     datetime.datetime.now() - datetime. | |||
|                                     datetime.strptime(create_time, | |||
|                                                       '%Y-%m-%d ' | |||
|                                                       '%H:%M:%S')).days | |||
|                             if diff_days >= rec.days_to_remove: | |||
|                                 requests.delete( | |||
|                                     "https://www.googleapis.com/drive/v3/" | |||
|                                     "files/%s" % | |||
|                                     file['id'], | |||
|                                     headers=headers) | |||
|                     if rec.notify_user: | |||
|                         mail_template_success.send_mail(rec.id, | |||
|                                                         force_send=True) | |||
|                 except Exception as e: | |||
|                     rec.generated_exception = e | |||
|                     _logger.info('Google Drive Exception: %s', e) | |||
|                     if rec.notify_user: | |||
|                         mail_template_failed.send_mail(rec.id, force_send=True) | |||
| 
 | 
| After Width: | Height: | Size: 3.6 KiB | 
| After Width: | Height: | Size: 310 B | 
| After Width: | Height: | Size: 1.3 KiB | 
| After Width: | Height: | Size: 1.4 KiB | 
| After Width: | Height: | Size: 576 B | 
| After Width: | Height: | Size: 733 B | 
| After Width: | Height: | Size: 911 B | 
| After Width: | Height: | Size: 1.1 KiB | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 3.4 KiB | 
| After Width: | Height: | Size: 673 B | 
| After Width: | Height: | Size: 878 B | 
| After Width: | Height: | Size: 653 B | 
| After Width: | Height: | Size: 905 B | 
| After Width: | Height: | Size: 839 B | 
| After Width: | Height: | Size: 427 B | 
| After Width: | Height: | Size: 627 B | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 988 B | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 537 KiB | 
| After Width: | Height: | Size: 128 KiB | 
| After Width: | Height: | Size: 137 KiB | 
| After Width: | Height: | Size: 159 KiB | 
| After Width: | Height: | Size: 104 KiB | 
| After Width: | Height: | Size: 108 KiB | 
| After Width: | Height: | Size: 162 KiB | 
| After Width: | Height: | Size: 52 KiB | 
| After Width: | Height: | Size: 56 KiB | 
| After Width: | Height: | Size: 56 KiB | 
| After Width: | Height: | Size: 78 KiB | 
| After Width: | Height: | Size: 66 KiB | 
| After Width: | Height: | Size: 48 KiB | 
| After Width: | Height: | Size: 56 KiB | 
| After Width: | Height: | Size: 126 KiB | 
| After Width: | Height: | Size: 113 KiB | 
| After Width: | Height: | Size: 53 KiB | 
| After Width: | Height: | Size: 61 KiB | 
| After Width: | Height: | Size: 76 KiB | 
| After Width: | Height: | Size: 52 KiB | 
| After Width: | Height: | Size: 121 KiB | 
| After Width: | Height: | Size: 50 KiB | 
| After Width: | Height: | Size: 16 KiB | 
| @ -0,0 +1,705 @@ | |||
| <div class="container" style="padding: 1rem !important; margin-bottom: 1rem !important;"> | |||
|   <div class="row"> | |||
|     <div class="col-sm-12 col-md-12 col-lg-12 d-flex justify-content-between" style="border-bottom: 1px solid #d5d5d5;"> | |||
|       <div class="my-3"> | |||
|         <img src="./assets/icons/logo.png" style="width: auto !important; height: 40px !important;"> | |||
|       </div> | |||
|       <div class="my-3 d-flex align-items-center"> | |||
|         <div | |||
|           style="background-color: #7C7BAD !important; color: #fff !important; font-weight: 600 !important; padding: 5px 15px 8px !important; margin: 0 5px !important;"> | |||
|           <i class="fa fa-check mr-1"></i>Community | |||
|         </div> | |||
|         <div | |||
|           style="background-color: #875A7B !important; color: #fff !important; font-weight: 600 !important; padding: 5px 15px 8px !important; margin: 0 5px !important;"> | |||
|           <i class="fa fa-check mr-1"></i>Enterprise | |||
|         </div> | |||
| 	<div | |||
|           style="background-color: #008080 !important; color: #fff !important; font-weight: 600 !important; padding: 5px 15px 8px !important; margin: 0 5px !important;"> | |||
|           <i class="fa fa-check mr-1"></i>Odoo.sh | |||
|         </div> | |||
|       </div> | |||
|     </div> | |||
|   </div> | |||
| </div> | |||
| 
 | |||
| <div class="container" style="padding: 0rem 1.5rem 4rem !important"> | |||
|   <div class="row" style="height: 900px !important;"> | |||
|     <div class="col-sm-12 col-md-12 col-lg-12" | |||
|       style="padding: 4rem 1rem !important; background-color: #714B67 !important; height: 600px !important; border-radius: 20px !important;"> | |||
|       <h1 | |||
|         style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #FFFFFF !important;  font-size: 3.5rem !important; text-align: center !important;"> | |||
|         Auto Database Backup</h1> | |||
|       <p | |||
|         style="font-family: 'Montserrat', sans-serif !important; font-weight: 300 !important; color: #FFFFFF !important;  font-size: 1.4rem !important; text-align: center !important;"> | |||
|         A Module For Generating Database Backup And Storing Backup To Multiple Locations. | |||
|       </p> | |||
|       <img src="./assets/screenshots/hero.gif" class="img-responsive" width="100%" height="auto" /> | |||
|     </div> | |||
|   </div> | |||
| 
 | |||
|   <div class="row"> | |||
|     <div class="col-md-12" style="border-bottom: 1px solid #d5d5d5 !important; margin-bottom: 2rem !important"> | |||
|       <h2 | |||
|         style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;"> | |||
|         <i class="fa fa-compass mr-2"></i>Explore this module | |||
|       </h2> | |||
|     </div> | |||
|     <div class="col-md-6"> | |||
|       <a href="#overview" style="text-decoration: none !important;"> | |||
|         <div class="row" | |||
|           style="background-color: #f5f2f5 !important; border-radius: 10px !important; margin: 1rem !important; padding: 1.5em !important; height: 100px !important;"> | |||
|           <div class="col-8"> | |||
|             <h3 | |||
|               style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.2rem !important;"> | |||
|               Overview</h3> | |||
|             <p | |||
|               style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #714B67 !important; font-size: 0.9rem !important;"> | |||
|               Learn more about this module</p> | |||
|           </div> | |||
|           <div class="col-4 text-right d-flex justify-content-end align-items-center"> | |||
|             <i class="fa fa-chevron-right" style="color: #714B67 !important;"></i> | |||
|           </div> | |||
|         </div> | |||
|       </a> | |||
|     </div> | |||
|     <div class="col-md-6"> | |||
|       <a href="#features" style="text-decoration: none !important;"> | |||
|         <div class="row" | |||
|           style="background-color: #f5f2f5 !important; border-radius: 10px !important; margin: 1rem !important; padding: 1.5em !important; height: 100px !important;"> | |||
|           <div class="col-8"> | |||
|             <h3 | |||
|               style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.2rem !important;"> | |||
|               Features</h3> | |||
|             <p | |||
|               style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #714B67 !important; font-size: 0.9rem !important;"> | |||
|               View features of this module</p> | |||
|           </div> | |||
|           <div class="col-4 text-right d-flex justify-content-end align-items-center"> | |||
|             <i class="fa fa-chevron-right" style="color: #714B67 !important;"></i> | |||
|           </div> | |||
|         </div> | |||
|       </a> | |||
|     </div> | |||
|     <div class="col-md-6"> | |||
|       <a href="#screenshots" style="text-decoration: none !important;"> | |||
|         <div class="row" | |||
|           style="background-color: #f5f2f5 !important; border-radius: 10px !important; margin: 1rem !important; padding: 1.5em !important; height: 100px !important;"> | |||
|           <div class="col-8"> | |||
|             <h3 | |||
|               style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.2rem !important;"> | |||
|               Screenshots</h3> | |||
|             <p | |||
|               style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #714B67 !important; font-size: 0.9rem !important;"> | |||
|               See key screenshots of this module</p> | |||
|           </div> | |||
|           <div class="col-4 text-right d-flex justify-content-end align-items-center"> | |||
|             <i class="fa fa-chevron-right" style="color: #714B67 !important;"></i> | |||
|           </div> | |||
|         </div> | |||
|       </a> | |||
|     </div> | |||
|   </div> | |||
| 
 | |||
| 
 | |||
|   <div class="row" id="overview"> | |||
|     <div class="col-md-12" style="border-bottom: 1px solid #d5d5d5 !important; margin: 2rem 0 !important"> | |||
|       <h2 | |||
|         style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;"> | |||
|         <i class="fa fa-pie-chart mr-2"></i>Overview | |||
|       </h2> | |||
|     </div> | |||
| 
 | |||
|     <div class="col-mg-12 pl-3"> | |||
|       <p | |||
|         style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important; line-height: 30px !important;"> | |||
|         This module helps to generate backups of your databases automatically on regular interval of times. | |||
|         The generated backups can be stored into local storage, ftp server, sftp server or Google Drive. | |||
|         User can enable auto remove option to automatically delete old backups. | |||
|         User can enable email notification to be notified about the success and failure of the backup generation and storage. | |||
|         Using Automatic Database Backup module user can generate and store database backups to multiple location.</p> | |||
| 
 | |||
|     </div> | |||
|   </div> | |||
| 
 | |||
| 
 | |||
|   <div class="row" id="features"> | |||
|     <div class="col-md-12" style="border-bottom: 1px solid #d5d5d5 !important; margin: 2rem 0 !important"> | |||
|       <h2 | |||
|         style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;"> | |||
|         <i class="fa fa-star mr-2"></i>Features | |||
|       </h2> | |||
|     </div> | |||
| 
 | |||
|     <div class="col-md-6 pl-3 py-3 d-flex"> | |||
|       <div> | |||
|         <img src="assets/icons/check.png"> | |||
|       </div> | |||
|       <div> | |||
|         <h4 | |||
|           style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | |||
|           Community & Enterprise Support</h4> | |||
|         <p | |||
|           style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | |||
|           Available in Odoo 12.0 Community and Enterprise.</p> | |||
|       </div> | |||
|     </div> | |||
|     <div class="col-md-6 pl-3 py-3 d-flex"> | |||
|       <div> | |||
|         <img src="assets/icons/check.png"> | |||
|       </div> | |||
|       <div> | |||
|         <h4 | |||
|           style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | |||
|           Generate Database Backup</h4> | |||
|         <p | |||
|           style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | |||
|           Generate database backups on regular intervals.</p> | |||
|       </div> | |||
|     </div> | |||
| 
 | |||
|     <div class="col-md-6 pl-3 py-3 d-flex"> | |||
|       <div> | |||
|         <img src="assets/icons/check.png"> | |||
|       </div> | |||
|       <div> | |||
|         <h4 | |||
|           style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | |||
|           Store Backup to FTP Server</h4> | |||
|         <p | |||
|           style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | |||
|           Generated backup can be stored to remote FTP server.</p> | |||
|       </div> | |||
|     </div> | |||
| 
 | |||
|     <div class="col-md-6 pl-3 py-3 d-flex"> | |||
|       <div> | |||
|         <img src="assets/icons/check.png"> | |||
|       </div> | |||
|       <div> | |||
|         <h4 | |||
|           style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | |||
|           Automatically Remove Old Backups.</h4> | |||
|         <p | |||
|           style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | |||
|           Old backups files will be deleted automatically based on the obsolescence of backup.</p> | |||
|       </div> | |||
|     </div> | |||
| 
 | |||
|     <div class="col-md-6 pl-3 py-3 d-flex"> | |||
|       <div> | |||
|         <img src="assets/icons/check.png"> | |||
|       </div> | |||
|       <div> | |||
|         <h4 | |||
|           style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | |||
|           Notify User On Success And Failure Of Backup Generation</h4> | |||
|         <p | |||
|           style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | |||
|           An email notification send to user on successful backup generation also send an email notification when backup operation failed.</p> | |||
|       </div> | |||
|     </div> | |||
| 
 | |||
|   </div> | |||
| 
 | |||
|   <div class="row" id="screenshots"> | |||
|     <div class="col-md-12" style="border-bottom: 1px solid #d5d5d5 !important; margin: 2rem 0 !important"> | |||
|       <h2 | |||
|         style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;"> | |||
|         <i class="fa fa-image mr-2"></i>Screenshots | |||
|       </h2> | |||
|     </div> | |||
|     <div class="col-lg-12 my-2"> | |||
|       <h4 class="mt-2" | |||
|         style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | |||
|         Database Backup Configuration Menu</h4> | |||
|       <p | |||
|         style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | |||
|         Got Setting --> Technical --> Backup Configuration to configure backups</p> | |||
|       <img src="assets/screenshots/backup1.png" class="img-responsive img-thumbnail border" width="100%" | |||
|         height="auto" /> | |||
|     </div> | |||
| 
 | |||
|     <div class="col-lg-12 my-3"> | |||
|       <h4 class="mt-3" | |||
|         style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | |||
|         Crate New Database Backup Configuration</h4> | |||
|       <p | |||
|         style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | |||
|         Enter the database name and master password. specify backup type and destination. | |||
|         Enter the backup directory path, if directory does not exist new directory will be created. | |||
|       </p> | |||
|       <img src="assets/screenshots/backup2.png" class="img-responsive img-thumbnail border" width="100%" | |||
|         height="auto" /> | |||
|     </div> | |||
| 
 | |||
|     <div class="col-lg-12 my-3"> | |||
|       <h4 class="mt-3" | |||
|         style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | |||
|         Store Backup to Remote SFTP Server</h4> | |||
|       <p | |||
|         style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | |||
|         Select backup destination as SFTP, enter credentials. | |||
|         Test connection button to check whether the connection is successful. | |||
|       </p> | |||
|       <img src="assets/screenshots/backup3.png" class="img-responsive img-thumbnail border" width="100%" | |||
|         height="auto" /> | |||
|     </div> | |||
| 
 | |||
| 
 | |||
|     <div class="col-lg-12 my-3"> | |||
|       <h4 class="mt-3" | |||
|         style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | |||
|         Store Backup to Remote FTP Server</h4> | |||
|       <p | |||
|         style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | |||
|         Select backup destination as FTP, enter credentials. | |||
|         Test connection button to check whether the connection is successful. | |||
|       </p> | |||
|       <img src="assets/screenshots/backup6.png" class="img-responsive img-thumbnail border" width="100%" | |||
|         height="auto" /> | |||
|     </div> | |||
| 
 | |||
| 
 | |||
|     <div class="col-lg-12 my-3"> | |||
|       <h4 class="mt-3" | |||
|         style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | |||
|         Store Backup to Google Drive</h4> | |||
|       <p | |||
|         style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | |||
|         Select backup destination as Google Drive. Enter google drive folder ID. | |||
|         Enable and configure Google Drive option from general settings. | |||
|       </p> | |||
|       <img src="assets/screenshots/backup7.png" class="img-responsive img-thumbnail border" width="100%" | |||
|         height="auto" /> | |||
| 
 | |||
|       <p | |||
|         style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | |||
|         Setup refresh token from general settings | |||
|       </p> | |||
|       <img src="assets/screenshots/backup8.png" class="img-responsive img-thumbnail border" width="100%" | |||
|         height="auto" /> | |||
|     </div> | |||
| 
 | |||
| 
 | |||
|     <div class="col-lg-12 my-3"> | |||
|       <h4 class="mt-3" | |||
|         style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | |||
|         Automatically Remove Old Backups</h4> | |||
|       <p | |||
|         style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | |||
|         Enable auto remove option, specify number of days to remove backups. | |||
|       </p> | |||
|       <img src="assets/screenshots/backup9.png" class="img-responsive img-thumbnail border" width="100%" | |||
|         height="auto" /> | |||
|     </div> | |||
| 
 | |||
|     <div class="col-lg-12 my-3"> | |||
|       <h4 class="mt-3" | |||
|         style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | |||
|         Notify User on Success and Failure of Backup Generation</h4> | |||
|       <p | |||
|         style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | |||
|         Enable notify user option, and select a user to notify. An email notification will be sent to the selected user on | |||
|         backup successful and failure. | |||
|         <img src="assets/screenshots/backup10.png" class="img-responsive img-thumbnail border" width="100%" | |||
|           height="auto" /> | |||
|     </div> | |||
| 
 | |||
|     <div class="col-lg-12 my-3"> | |||
|       <h4 class="mt-3" | |||
|         style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | |||
|         Successful backup notification email</h4> | |||
|       <img src="assets/screenshots/backup12.png" class="img-responsive img-thumbnail border" width="100%" | |||
|         height="auto" /> | |||
|     </div> | |||
| 
 | |||
|     <div class="col-lg-12 my-3"> | |||
|       <h4 class="mt-3" | |||
|         style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | |||
|         Notification email when backup generation failed</h4> | |||
|       <img src="assets/screenshots/backup11.png" class="img-responsive img-thumbnail border" width="100%" | |||
|         height="auto" /> | |||
|     </div> | |||
| 
 | |||
| 
 | |||
|     <div class="col-lg-12 my-3"> | |||
|       <h4 class="mt-3" | |||
|         style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | |||
|         Scheduled Action For Generating Backup</h4> | |||
|       <p | |||
|         style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | |||
| 
 | |||
|         Enable the 'Automatic database Backup' scheduled action, and set up the execution interval. | |||
|         Based on the scheduled action setup, backups will be generated on regular intervals. | |||
|       </p> | |||
|       <img src="assets/screenshots/backup13.png" class="img-responsive img-thumbnail border" width="100%" | |||
|         height="auto" /> | |||
|       <img src="assets/screenshots/backup14.png" class="img-responsive img-thumbnail border" width="100%" | |||
|         height="auto" /> | |||
|     </div> | |||
| 
 | |||
|   </div> | |||
| 
 | |||
| 
 | |||
|   <!-- SUGGESTED PRODUCTS --> | |||
|   <div class="row"> | |||
|     <div class="col-lg-12 d-flex flex-column justify-content-center" | |||
|       style="text-align: center; padding: 2.5rem 1rem !important;"> | |||
|       <h2 style="color: #212529 !important;">Suggested Products</h2> | |||
|       <hr | |||
|         style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;" /> | |||
| 
 | |||
|       <div id="demo1" class="row carousel slide" data-ride="carousel"> | |||
|         <!-- The slideshow --> | |||
|         <div class="carousel-inner"> | |||
|           <div class="carousel-item active" style="min-height:0px"> | |||
|             <div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left"> | |||
|               <a href="https://apps.odoo.com/apps/modules/12.0/hr_zk_attendance/" target="_blank"> | |||
|                 <div style="border-radius:10px"> | |||
|                   <img class="img img-responsive center-block" | |||
|                     style="border-top-left-radius:10px; border-top-right-radius:10px" | |||
|                     src="./assets/modules/banner.gif"> | |||
|                 </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/12.0/login_user_detail/" target="_blank"> | |||
|                 <div style="border-radius:10px"> | |||
|                   <img class="img img-responsive center-block" | |||
|                     style="border-top-left-radius:10px; border-top-right-radius:10px" | |||
|                     src="./assets/modules/banner.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/12.0/fleet_rental/" target="_blank"> | |||
|                 <div style="border-radius:10px"> | |||
|                   <img class="img img-responsive center-block" | |||
|                     style="border-top-left-radius:10px; border-top-right-radius:10px" | |||
|                     src="./assets/modules/banner1.jpg"> | |||
|                 </div> | |||
|               </a> | |||
|             </div> | |||
|           </div> | |||
|           <div class="carousel-item" style="min-height:0px"> | |||
|             <div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left"> | |||
|               <a href="https://apps.odoo.com/apps/modules/12.0/oh_hr_zk_attendance/" target="_blank"> | |||
|                 <div style="border-radius:10px"> | |||
|                   <img class="img img-responsive center-block" | |||
|                     style="border-top-left-radius:10px; border-top-right-radius:10px" | |||
|                     src="./assets/modules/banner2.jpg"> | |||
|                 </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/12.0/product_barcode/" target="_blank"> | |||
|                 <div style="border-radius:10px"> | |||
|                   <img class="img img-responsive center-block" | |||
|                     style="border-top-left-radius:10px; border-top-right-radius:10px" | |||
|                     src="./assets/modules/banner3.jpg"> | |||
|                 </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/12.0/project_task_timer/" target="_blank"> | |||
|                 <div style="border-radius:10px"> | |||
|                   <img class="img img-responsive center-block" | |||
|                     style="border-top-left-radius:10px; border-top-right-radius:10px" | |||
|                     src="./assets/modules/banner4.jpg"> | |||
|                 </div> | |||
|               </a> | |||
|             </div> | |||
|           </div> | |||
|         </div> | |||
|         <!-- Left and right controls --> | |||
|         <a class="carousel-control-prev" href="#demo1" data-slide="prev" style="left:-25px;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="right:-25px;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 SUGGESTED PRODUCTS --> | |||
| 
 | |||
|   <!-- OUR SERVICES --> | |||
|   <section class="container" style="margin-top: 6rem !important;"> | |||
|     <div class="row"> | |||
|       <div class="col-lg-12 d-flex flex-column justify-content-center align-items-center"> | |||
|         <h2 style="color: #212529 !important;">Our Services</h2> | |||
|         <hr | |||
|           style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;" /> | |||
|       </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: #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> | |||
|   </section> | |||
|   <!-- END OF OUR SERVICES --> | |||
| 
 | |||
|   <!-- OUR INDUSTRIES --> | |||
|   <section class="container" style="margin-top: 6rem !important;"> | |||
|     <div class="row"> | |||
|       <div class="col-lg-12 d-flex flex-column justify-content-center align-items-center"> | |||
|         <h2 style="color: #212529 !important;">Our Industries</h2> | |||
|         <hr | |||
|           style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;" /> | |||
|       </div> | |||
| 
 | |||
|       <div class="col-lg-3"> | |||
|         <div class="my-4 d-flex flex-column justify-content-center" | |||
|           style="background-color: #f6f8f9 !important; border-radius: 10px; 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: 10px; 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: 10px; 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: 10px; 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: 10px; 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 & 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: 10px; 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: 10px; 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: 10px; 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> | |||
|   </section> | |||
| 
 | |||
|   <!-- END OF OUR INDUSTRIES --> | |||
| 
 | |||
|   <!-- FOOTER --> | |||
|   <!-- Footer Section --> | |||
|   <section class="container" style="margin: 5rem auto 2rem;"> | |||
|     <div class="row" style="max-width:1540px;"> | |||
|       <div class="col-lg-12 d-flex flex-column justify-content-center align-items-center"> | |||
|         <h2 style="color: #212529 !important;">Need Help?</h2> | |||
|         <hr | |||
|           style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;" /> | |||
|       </div> | |||
|     </div> | |||
| 
 | |||
|     <!-- Contact Cards --> | |||
|     <div class="row d-flex justify-content-center align-items-center" | |||
|       style="max-width:1540px; margin: 0 auto 2rem auto;"> | |||
| 
 | |||
|       <div class="col-lg-12" style="padding: 0rem 3rem 2rem; border-radius: 10px; margin-right: 3rem; "> | |||
| 
 | |||
|         <div class="row mt-4"> | |||
|           <div class="col-lg-6"> | |||
|             <a href="mailto:odoo@cybrosys.com" target="_blank" class="btn btn-block mb-2 deep_hover" | |||
|               style="text-decoration: none;  background-color: #4d4d4d; color: #FFF;  border-radius: 4px;"><i | |||
|                 class="fa fa-envelope mr-2"></i>odoo@cybrosys.com</a> | |||
|           </div> | |||
|           <div class="col-lg-6"> | |||
|             <a href="https://api.whatsapp.com/send?phone=918606827707" target="_blank" | |||
|               class="btn btn-block mb-2 deep_hover" | |||
|               style="text-decoration: none;  background-color: #25D366; color: #FFF;  border-radius: 4px;"><i | |||
|                 class="fa fa-whatsapp mr-2"></i>+91 86068 27707</a> | |||
|           </div> | |||
|         </div> | |||
|       </div> | |||
| 
 | |||
|     </div> | |||
|     <!-- End of Contact Cards --> | |||
|   </section> | |||
|   <!-- Footer --> | |||
|   <section class="oe_container" style="padding: 2rem 3rem 1rem;"> | |||
|     <div class="row" style="max-width:1540px; margin: 0 auto; margin-right: 3rem; "> | |||
|       <!-- Logo --> | |||
|       <div class="col-lg-12 d-flex justify-content-center align-items-center" style="margin-top: 3rem;"> | |||
|         <img src="https://www.cybrosys.com/images/logo.png" width="200px" height="auto" /> | |||
|       </div> | |||
|       <!-- End of Logo --> | |||
|       <div class="col-lg-12"> | |||
|         <hr | |||
|           style="margin-top: 3rem;background: linear-gradient(90deg, rgba(2,0,36,0) 0%, rgba(229,229,229,1) 33%, rgba(229,229,229,1) 58%, rgba(0,212,255,0) 100%); height: 2px; border-style: none;"> | |||
|         <!-- End of Footer Section --> | |||
|       </div> | |||
|     </div> | |||
|   </section> | |||
|   <!-- END OF FOOTER --> | |||
| 
 | |||
| </div> | |||
| @ -0,0 +1,131 @@ | |||
| <?xml version="1.0" encoding="utf-8" ?> | |||
| <odoo> | |||
|     <!-- Defines the list view for database backup configuration--> | |||
|     <record id="db_backup_configure_view_list" model="ir.ui.view"> | |||
|         <field name="name">db.backup.configure.view.list</field> | |||
|         <field name="model">db.backup.configure</field> | |||
|         <field name="arch" type="xml"> | |||
|             <tree decoration-muted="(not active)"> | |||
|                 <field name="name"/> | |||
|                 <field name="db_name"/> | |||
|                 <field name="backup_destination"/> | |||
|                 <field name="active"/> | |||
|             </tree> | |||
|         </field> | |||
|     </record> | |||
|     <!--Defines the form view for database backup configuration.--> | |||
|     <record id="db_backup_configure_view_form" model="ir.ui.view"> | |||
|         <field name="name">db.backup.configure.view.form</field> | |||
|         <field name="model">db.backup.configure</field> | |||
|         <field name="arch" type="xml"> | |||
|             <form> | |||
|                 <sheet> | |||
|                     <div class="oe_title"> | |||
|                         <h1> | |||
|                             <field name="name" placeholder="Name..."/> | |||
|                         </h1> | |||
|                     </div> | |||
|                     <group> | |||
|                         <group> | |||
|                             <field name="db_name"/> | |||
|                             <field name="master_pwd" password="True"/> | |||
|                             <field name="backup_format"/> | |||
|                             <field name="active" widget="boolean_toggle"/> | |||
|                         </group> | |||
|                         <group> | |||
|                             <field name="backup_destination" required="1"/> | |||
|                             <div class="text-muted" | |||
|                                  attrs="{'invisible': [('backup_destination', '!=', 'google_drive')]}"> | |||
|                                 Enable and | |||
|                                 configure Google Drive option from General | |||
|                                 Settings | |||
|                             </div> | |||
|                             <field name="backup_path" | |||
|                                    attrs="{'invisible': [('backup_destination', '!=', 'local')], 'required': [('backup_destination', '=', 'local')]}"/> | |||
|                             <field name="ftp_host" | |||
|                                    attrs="{'invisible': [('backup_destination', '!=', 'ftp')], 'required': [('backup_destination', '=', 'ftp')]}"/> | |||
|                             <field name="ftp_port" | |||
|                                    attrs="{'invisible': [('backup_destination', '!=', 'ftp')], 'required': [('backup_destination', '=', 'ftp')]}"/> | |||
|                             <field name="ftp_user" | |||
|                                    attrs="{'invisible': [('backup_destination', '!=', 'ftp')], 'required': [('backup_destination', '=', 'ftp')]}"/> | |||
|                             <field name="ftp_password" | |||
|                                    attrs="{'invisible': [('backup_destination', '!=', 'ftp')], 'required': [('backup_destination', '=', 'ftp')]}" | |||
|                                    password="True"/> | |||
|                             <field name="ftp_path" | |||
|                                    attrs="{'invisible': [('backup_destination', '!=', 'ftp')], 'required': [('backup_destination', '=', 'ftp')]}"/> | |||
|                             <field name="sftp_host" | |||
|                                    attrs="{'invisible': [('backup_destination', '!=', 'sftp')], 'required': [('backup_destination', '=', 'sftp')]}"/> | |||
|                             <field name="sftp_port" | |||
|                                    attrs="{'invisible': [('backup_destination', '!=', 'sftp')], 'required': [('backup_destination', '=', 'sftp')]}"/> | |||
|                             <field name="sftp_user" | |||
|                                    attrs="{'invisible': [('backup_destination', '!=', 'sftp')], 'required': [('backup_destination', '=', 'sftp')]}"/> | |||
|                             <field name="sftp_password" | |||
|                                    attrs="{'invisible': [('backup_destination', '!=', 'sftp')], 'required': [('backup_destination', '=', 'sftp')]}" | |||
|                                    password="True"/> | |||
|                             <field name="sftp_path" | |||
|                                    attrs="{'invisible': [('backup_destination', '!=', 'sftp')], 'required': [('backup_destination', '=', 'sftp')]}"/> | |||
|                             <field name="google_drive_folder" | |||
|                                    attrs="{'invisible': [('backup_destination', '!=', 'google_drive')], 'required': [('backup_destination', '=', 'google_drive')]}"/> | |||
|                             <field name="auto_remove"/> | |||
|                             <label for="days_to_remove" class="oe_inline" | |||
|                                    attrs="{'invisible': [('auto_remove', '=', False)]}"/> | |||
|                             <div attrs="{'invisible': [('auto_remove', '=', False)]}"> | |||
|                                 <field name="days_to_remove" class="oe_inline" | |||
|                                        attrs="{'required': [('auto_remove', '=', True)]}"/> | |||
|                                 Days | |||
|                             </div> | |||
|                             <button name="test_connection" type="object" | |||
|                                     string="Test Connection" | |||
|                                     icon="fa-television" | |||
|                                     attrs="{'invisible': [('backup_destination', 'not in', ('ftp', 'sftp'))]}"/> | |||
|                         </group> | |||
|                         <group> | |||
|                             <field name="notify_user"/> | |||
|                             <field name="user_id" | |||
|                                    attrs="{'invisible': [('notify_user', '=', False)]}"/> | |||
|                         </group> | |||
|                     </group> | |||
|                 </sheet> | |||
|             </form> | |||
|         </field> | |||
|     </record> | |||
|     <!--Defines the search view for database backup configuration.--> | |||
|     <record id="db_backup_configure_view_search" model="ir.ui.view"> | |||
|         <field name="name">db.backup.configure.view.search</field> | |||
|         <field name="model">db.backup.configure</field> | |||
|         <field name="arch" type="xml"> | |||
|             <search> | |||
|                 <field name="name"/> | |||
|                 <field name="db_name"/> | |||
|                 <filter string="All" name="all" | |||
|                         domain="['|', ('active', '=',  True), ('active', '!=',  True)]"/> | |||
|                 <separator/> | |||
|                 <filter string="Archived" name="inactive" | |||
|                         domain="[('active', '=', False)]"/> | |||
|                 <group expand="0" string="Group By"> | |||
|                     <filter string="Backup Type" name="backup_type" domain="[]" | |||
|                             context="{'group_by': 'backup_destination'}"/> | |||
|                 </group> | |||
|             </search> | |||
|         </field> | |||
|     </record> | |||
|     <!--Defines the action window for accessing database backup configurations.--> | |||
|     <record id="action_db_backup_configure" model="ir.actions.act_window"> | |||
|         <field name="name">Database Backup</field> | |||
|         <field name="res_model">db.backup.configure</field> | |||
|         <field name="view_mode">tree,form</field> | |||
|         <field name="help" type="html"> | |||
|             <p class="o_view_nocontent_smiling_face"> | |||
|                 No backup configured! | |||
|             </p> | |||
|         </field> | |||
|         <field name="context">{'search_default_all': 1}</field> | |||
|     </record> | |||
|     <!--Defines the menu item for accessing automatic database backup configurations.--> | |||
|     <menuitem id="menu_db_backup" name="Automatic Database Backup" | |||
|               parent="base.menu_custom" sequence="10"/> | |||
|     <!--Defines the submenu item for accessing backup configuration under the "Automatic Database Backup" menu.   --> | |||
|     <menuitem id="menu_db_backup_configuration" parent="menu_db_backup" | |||
|               name="Backup Configuration" | |||
|               action="action_db_backup_configure"/> | |||
| </odoo> | |||