Odoo deals with multiple business documents such as invoices, bills and many other. No matter what kind of reports, one can backup these business documents into a server using the SFTP transfer protocol in Odoo.
SFTP Transfer Protocol
SFTP stands for Secure File Transfer Protocol. SFTP transfer protocol is one of the most popular and secure methods of file transfer between two remote systems. It comes within the SSH, however, works in a separate package over a secured connection. SFTP is always preferred over FTP (File Transfer Protocol) because of SFTP’s underlying security features and its ability to piggy-back on an SSH connection. The default port number of SFTP protocol is port 22.
In order to transfer files to a remote server, we are using python library pysftp.
Before using the library, one must ensure that it is installed in your system.
pip3 install pysftp
Then Import pysftp
import pysftp
To test connection:
my_host = "local ip address"
my_username = "user"
my_password = "password"
with pysftp.Connection(host=my_host, username=my_username, password=my_password) as sftp:
print "Connection succesfully established ... "
If the connection is successfully established, set the remote location path and local file path.
remote_path = '/var/sftp/file/'
local_path = './file.pdf'
Then pass the variables in sftp.put()
sftp.put(local_path, remote_path)
the connection will automatically close at the end of the with-block.
In odoo, we are using the same python library pysftp.
Create a module for SFTP backup. Create a model for SFTP configuration.
from odoo import models, fields, api
from odoo.exceptions import Warning
import base64
import tempfile
import os
try:
import pysftp
except ImportError:
raise ImportError(
'This module needs pysftp to automatically write backups to the FTP through SFTP. Please install pysftp '
'on your system. (sudo pip3 install pysftp)')
class FileBackup(models.Model):
_name = 'sftp.backup'
_rec_name = 'sftp_host'
sftp_host = fields.Char(string="Host", required=True)
sftp_path = fields.Char("Backup Directory Path", required=True)
sftp_user = fields.Char("Username", required=True)
sftp_password = fields.Char("Password", required=True)
sftp_hostkeys = fields.Char("Hostkeys")
Create a button in the configuration form for testing connection.
<!-- Form View of SFTP Configuration -->
<record id="sftp_config_view" model="ir.ui.view">
<field name="name">backup.sftp.conf</field>
<field name="model">sftp.backup</field>
<field name="arch" type="xml">
<form>
<header>
<button name='sftp_test_connection' string="SFTP Test Connection" type="object" class="oe_highlight" groups="base.group_user"/>
</header>
<sheet>
<group name="" style="width:80%;">
<field name="sftp_host"/>
<field name="sftp_user"/>
<field name="sftp_password"/>
<field name="sftp_path"/>
<field name="sftp_hostkeys"/>
</group>
</sheet>
</form>
</field>
</record>
</data>
</odoo>
To test the connection with SFTP server:
def sftp_test_connection(self):
self.ensure_one()
for rec in self:
file_path = rec.sftp_path
ip_host = rec.sftp_host
username_login = rec.sftp_user
password_login = rec.sftp_password
hostkeys = rec.sftp_hostkeys
if hostkeys:
cnopts = pysftp.CnOpts()
cnopts.hostkeys.load(hostkeys)
else:
cnopts = pysftp.CnOpts()
cnopts.hostkeys = None
# Connect with external server over SFTP, so we know sure that everything works.
try:
with pysftp.Connection(host=ip_host, username=username_login, password=password_login, cnopts=cnopts) as sftp:
sftp.cwd(file_path)
except Exception as e:
raise Warning('There was a problem connecting to the remote ftp: ' + str(e))
raise Warning("Connection Success!!!")
If the connection gets established, you can backup your file to SFTP server.
Here, taking the example of SFTP transfer of the PDF file of each invoice. So first stored all the pdf invoices into a binary field pdf and boolean field transfer in model ‘account.invoice’.
Then defined a function for SFTP transfer.
def sftp_backup(self):
conf_ids = self.search([])
invoices = self.env['account.invoice'].search([])
for rec in conf_ids:
try:
# Store all values in variables
path = rec.sftp_path
ip_host = rec.sftp_host
username = rec.sftp_user
password = rec.sftp_password
hostkeys = rec.sftp_hostkeys
if hostkeys:
cnopts = pysftp.CnOpts()
cnopts.hostkeys.load(hostkeys)
else:
cnopts = pysftp.CnOpts()
cnopts.hostkeys = None
# Establishing connection with SFTP Server
with pysftp.Connection(host=ip_host, username=username, password=password) as sftp:
for inv in invoices:
# Check the invoices which have pdf files and which files are not transferred before
if inv.pdf and inv.transfer is False:
try:
# creating temporary files to store the transferring file
temp = tempfile.NamedTemporaryFile(mode='w+t')
temp.writelines(base64.decodestring(inv.pdf).decode('utf-8'))
temp.seek(0)
filename = inv.pdf_name
# transfer file, specify the path and file name
try:
sftp.put(temp.name, os.path.join(path, filename))
inv.transfer = True
except Exception as e:
raise Warning('Exception! We couldn\'t back up to the SFTP server..' + str(e))
finally:
temp.close()
except Exception as e:
raise Warning('Exception! We couldn\'t back up to the SFTP server..' + str(e))