예제 #1
0
    def _update_form_view_from_env(self, arch, view_type):
        if view_type != "form":
            return arch
        current_env = self.env.context.get("environment") or config.get(
            "running_env")
        # Important to keep this list sorted. It makes sure the button to
        # switch environment will always be in the same order. (more user
        # friendly) and the test would fail without it as the order could
        # change randomly and the view would then also change randomly
        other_environments = sorted([
            key[15:] for key, val in config.options.items()
            if key.startswith("encryption_key_") and val
            and key[15:] != current_env
        ])

        if not current_env:
            raise ValidationError(
                _("you need to define the running_env entry in your odoo "
                  "configuration file"))
        doc = etree.XML(arch)
        node = doc.xpath("//sheet")
        if node:
            node = node[0]
            elem = self._get_extra_environment_info_div(
                current_env, other_environments)
            node.insert(0, elem)

            if current_env != config.get("running_env"):
                self._set_readonly_form_view(doc)
            arch = etree.tostring(doc, pretty_print=True, encoding="unicode")
        else:
            _logger.error("Missing sheet for form view on object {}".format(
                self._name))
        return arch
예제 #2
0
class SmbConfig:
    """" Little class who contains SMB configuration """

    smb_user = config.get("smb_user")
    smb_pass = config.get("smb_pwd")
    smb_ip = config.get("smb_ip")
    smb_port = int(config.get("smb_port", 0))
 def _retrieve_token(self):
     """ Retrieves the token from Connect. """
     client = config.get('connect_client')
     secret = config.get('connect_secret')
     environment = config.get('connect_env', 'core')
     if not client or not secret:
         raise UserError(
             _('Please give connect_client and connect_secret values '
               'in your Odoo configuration file.'))
     api_client_secret = base64.b64encode("{0}:{1}".format(client, secret))
     params_post = 'grant_type=client_credentials&scope=read+write'
     header_post = {
         "Authorization": "Basic " + api_client_secret,
         "Content-type": "application/x-www-form-urlencoded",
         "Content-Length": 46,
         "Expect": "100-continue",
         "Connection": "Keep-Alive"
     }
     conn = httplib.HTTPSConnection('api2.compassion.com')
     auth_path = "/{}/connect/token".format(environment)
     conn.request("POST", auth_path, params_post, header_post)
     response = conn.getresponse()
     try:
         self._token = simplejson.loads(response.read())
         self._token_time = datetime.now()
         self._session.headers.update({
             'Authorization':
             '{token_type} {access_token}'.format(**self._token)
         })
     except (AttributeError, KeyError):
         raise UserError(_('Token validation failed.'))
 def _retrieve_token(self):
     """ Retrieves the token from Connect. """
     client = config.get('connect_client')
     secret = config.get('connect_secret')
     environment = config.get('connect_env', 'core')
     if not client or not secret:
         raise UserError(
             _('Please give connect_client and connect_secret values '
               'in your Odoo configuration file.'))
     api_client_secret = base64.b64encode("{0}:{1}".format(client, secret))
     params_post = 'grant_type=client_credentials&scope=read+write'
     header_post = {
         "Authorization": "Basic " + api_client_secret,
         "Content-type": "application/x-www-form-urlencoded",
         "Content-Length": 46,
         "Expect": "100-continue",
         "Connection": "Keep-Alive"}
     conn = httplib.HTTPSConnection('api2.compassion.com')
     auth_path = "/{}/connect/token".format(environment)
     conn.request("POST", auth_path, params_post, header_post)
     response = conn.getresponse()
     try:
         self._token = simplejson.loads(response.read())
         self._token_time = datetime.now()
         self._session.headers.update({
             'Authorization': '{token_type} {access_token}'.format(
                 **self._token)})
     except (AttributeError, KeyError):
         raise UserError(
             _('Token validation failed.'))
예제 #5
0
class SmbConfig():
    """" Little class who contains SMB configuration """
    smb_user = config.get('smb_user')
    smb_pass = config.get('smb_pwd')
    smb_ip = config.get('smb_ip')
    smb_port = int(config.get('smb_port', 0))
    file_pw = config.get('partner_data_password')
 def get_gmc_token(cls):
     """
     Class method that fetches a token from GMC OAuth server.
     :return: dict: Authorisation header.
     """
     client = config.get('connect_client')
     secret = config.get('connect_secret')
     provider = config.get('connect_token_server')
     endpoint = config.get('connect_token_endpoint')
     if not client or not secret or not provider or not endpoint:
         raise UserError(
             _('Please give connect_client, connect_secret, '
               'connect_token_server and connect_token_endpoint '
               'in your Odoo configuration file.'))
     api_client_secret = base64.b64encode("{0}:{1}".format(client, secret))
     params_post = 'grant_type=client_credentials&scope=read+write'
     header_post = {
         "Authorization": "Basic " + api_client_secret,
         "Content-type": "application/x-www-form-urlencoded",
         "Content-Length": 46,
         "Expect": "100-continue",
         "Connection": "Keep-Alive"
     }
     conn = httplib.HTTPSConnection(provider)
     conn.request("POST", endpoint, params_post, header_post)
     response = conn.getresponse()
     try:
         token = simplejson.loads(response.read())
         return {
             'Authorization': '{token_type} {access_token}'.format(**token)
         }
     except (AttributeError, KeyError):
         _logger.error("GMC token retrieval error", exc_info=True)
         raise UserError(_('Token validation failed.'))
예제 #7
0
    def _transfer_file_on_nas(self, file_name):
        """
        Puts the letter file on the NAS folder for the translation platform.
        :return: None
        """
        self.ensure_one()
        # Retrieve configuration
        smb_user = config.get('smb_user')
        smb_pass = config.get('smb_pwd')
        smb_ip = config.get('smb_ip')
        smb_port = int(config.get('smb_port', 0))
        if not (smb_user and smb_pass and smb_ip and smb_port):
            raise Exception('No config SMB in file .conf')

        # Copy file in the imported letter folder
        smb_conn = SMBConnection(smb_user, smb_pass, 'openerp', 'nas')
        if smb_conn.connect(smb_ip, smb_port):
            file_ = BytesIO(base64.b64decode(self.letter_image))
            nas_share_name = self.env.ref(
                'sbc_switzerland.nas_share_name').value

            nas_letters_store_path = self.env.ref(
                'sbc_switzerland.nas_letters_store_path').value + file_name
            smb_conn.storeFile(nas_share_name, nas_letters_store_path, file_)

            logger.info('File {} store on NAS with success'.format(
                self.file_name))
        else:
            raise UserError(_('Connection to NAS failed'))
예제 #8
0
 def import_prod_categ(self):
     username = config.get("app_user")
     pwd = config.get("app_pwd")
     dbname = config.get("app_db")
     file_import_path = os.path.dirname(os.path.abspath(__file__))
     url = self.env['ir.config_parameter'].get_param('web.base.url')
     sock_common = xmlrpclib.ServerProxy(url + "/xmlrpc/common")
     uid = sock_common.login(dbname, username, pwd)
     sock = xmlrpclib.ServerProxy(url + "/xmlrpc/object")
     reader = csv.reader(open(
         file_import_path + '/../import/product_category.csv', 'rb'),
                         delimiter='|',
                         quotechar='"')
     for row in reader:
         categ = self.env['product.category'].search([('name', '=',
                                                       row[0].strip())])
         if categ:
             _logger.error(row[0] + " Already exist")
         else:
             product_categ = {
                 'name': row[0].strip(),
                 'parent_id': 1,  # Product category called 'All'
                 'type': 'normal'
             }
             template_id = sock.execute(dbname, uid, pwd,
                                        'product.category', 'create',
                                        product_categ)
             self.create({
                 'model': 'product.category',
                 'item_id': template_id,
                 'action_date': fields.Date.context_today(self)
             })
     return {}
예제 #9
0
 def import_uom(self):
     username = config.get("app_user")
     pwd = config.get("app_pwd")
     dbname = config.get("app_db")
     file_import_path = os.path.dirname(os.path.abspath(__file__))
     url = self.env['ir.config_parameter'].get_param('web.base.url')
     sock_common = xmlrpclib.ServerProxy(url + "/xmlrpc/common")
     uid = sock_common.login(dbname, username, pwd)
     sock = xmlrpclib.ServerProxy(url + "/xmlrpc/object")
     reader = csv.reader(open(
         file_import_path + '/../import/product_uom.csv', 'rb'),
                         delimiter='|',
                         quotechar='"')
     for row in reader:
         uom = self.env['product.uom'].search([('name', '=', row[0].strip())
                                               ])
         if uom:
             _logger.error(row[0] + " Already exist")
         else:
             product_uom = {
                 'name': row[0].strip(),
                 'category_id': 6,  # UoM category called 'Imported'
                 'uom_type': 'reference',
                 'rounding': 0.00100
             }
             template_id = sock.execute(dbname, uid, pwd, 'product.uom',
                                        'create', product_uom)
             self.create({
                 'model': 'product.uom',
                 'item_id': template_id,
                 'action_date': fields.Date.context_today(self)
             })
     return {}
예제 #10
0
 def test_config_set(self):
     """Test that the config is properly set on the server
     """
     url = config.get('compass_url')
     api_key = config.get('compass_api_key')
     self.assertTrue(url)
     self.assertTrue(api_key)
    def _transfer_file_on_nas(self, file_name):
        """
        Puts the letter file on the NAS folder for the translation platform.
        :return: None
        """
        self.ensure_one()
        # Retrieve configuration
        smb_user = config.get("smb_user")
        smb_pass = config.get("smb_pwd")
        smb_ip = config.get("smb_ip")
        smb_port = int(config.get("smb_port", 0))
        if not (smb_user and smb_pass and smb_ip and smb_port):
            raise Exception("No config SMB in file .conf")

        # Copy file in the imported letter folder
        smb_conn = SMBConnection(smb_user, smb_pass, "openerp", "nas")
        if smb_conn.connect(smb_ip, smb_port):
            file_ = BytesIO(self.get_image())
            nas_share_name = self.env.ref(
                "sbc_switzerland.nas_share_name").value

            nas_letters_store_path = (
                self.env.ref("sbc_switzerland.nas_letters_store_path").value +
                file_name)
            smb_conn.storeFile(nas_share_name, nas_letters_store_path, file_)
        else:
            raise UserError(_("Connection to NAS failed"))
    def _transfer_file_on_nas(self, file_name):
        """
        Puts the letter file on the NAS folder for the translation platform.
        :return: None
        """
        self.ensure_one()
        # Retrieve configuration
        smb_user = config.get('smb_user')
        smb_pass = config.get('smb_pwd')
        smb_ip = config.get('smb_ip')
        smb_port = int(config.get('smb_port', 0))
        if not (smb_user and smb_pass and smb_ip and smb_port):
            raise Exception('No config SMB in file .conf')

        # Copy file in the imported letter folder
        smb_conn = SMBConnection(smb_user, smb_pass, 'openerp', 'nas')
        if smb_conn.connect(smb_ip, smb_port):
            file_ = BytesIO(base64.b64decode(self.letter_image))
            nas_share_name = self.env.ref(
                'sbc_switzerland.nas_share_name').value

            nas_letters_store_path = self.env.ref(
                'sbc_switzerland.nas_letters_store_path').value + file_name
            smb_conn.storeFile(nas_share_name,
                               nas_letters_store_path, file_)

            logger.info('File {} store on NAS with success'
                        .format(self.file_name))
        else:
            raise UserError(_('Connection to NAS failed'))
예제 #13
0
 def get_gmc_token(cls):
     """
     Class method that fetches a token from GMC OAuth server.
     :return: dict: Authorisation header.
     """
     client = config.get("connect_client")
     secret = config.get("connect_secret")
     provider = config.get("connect_token_server")
     if not client or not secret or not provider:
         raise UserError(
             _("Please give connect_client, connect_secret, "
               "connect_token_server in your Odoo configuration file."))
     params_post = "grant_type=client_credentials&scope=read+write"
     header_post = {
         "Content-type": "application/x-www-form-urlencoded",
         "Content-Length": "46",
         "Expect": "100-continue",
         "Connection": "Keep-Alive",
     }
     response = requests.post(provider,
                              data=params_post,
                              auth=(client, secret),
                              headers=header_post)
     try:
         token = response.json()
         return {
             "Authorization": "{token_type} {access_token}".format(**token)
         }
     except (AttributeError, KeyError, JSONDecodeError):
         _logger.error("GMC token retrieval error: %s",
                       response.text,
                       exc_info=True)
         raise UserError(_("Token validation failed."))
 def test_config_set(self):
     """Test that the config is properly set on the server
     """
     url = config.get('compass_url')
     api_key = config.get('compass_api_key')
     self.assertTrue(url)
     self.assertTrue(api_key)
class SftpConfig:
    """" Little class who contains SMB configuration """

    username = config.get("sftp_user")
    password = config.get("sftp_pwd")
    host = config.get("sftp_ip")
    port = int(config.get("sftp_port", 22))
    file_pw = config.get("partner_data_password")
class SmbConfig:
    """" Little class who contains SMB configuration """

    smb_user = config.get("smb_user")
    smb_pass = config.get("smb_pwd")
    smb_ip = config.get("smb_ip")
    smb_port = int(config.get("smb_port", 0))
    file_pw = config.get("partner_data_password")
예제 #17
0
 def __init__(self):
     Thread.__init__(self)
     self.queue = Queue()
     self.lock = Lock()
     self.status = {'status': 'connecting', 'messages': []}
     self.device_name = config.get('telium_terminal_device_name',
                                   '/dev/ttyACM0')
     self.device_rate = int(config.get('telium_terminal_device_rate', 9600))
     self.serial = False
예제 #18
0
 def wrap(*args, **kwargs):
     if not system_base_config.get("running_env"):
         system_base_config["running_env"] = "test"
     server_running_state = system_base_config.get("running_env")
     if server_running_state == "prod":
         result = func(*args, **kwargs)
     else:
         logger.info("Server state != prod, ignored %s function" % func.__name__)
         result = False
     return result
예제 #19
0
def config_to_enable_email_sending(enable_email_sending):
    init_config = {
        'enable_email_sending': config.get('enable_email_sending'),
        'test_enable': config.get('test_enable'),
    }
    try:
        config['enable_email_sending'] = enable_email_sending
        config['test_enable'] = not enable_email_sending
        yield config
    finally:
        for key, value in init_config.items():
            config[key] = value
예제 #20
0
 def __init__(self):
     Thread.__init__(self)
     self.queue = Queue()
     self.lock = Lock()
     self.status = {'status': 'connecting', 'messages': []}
     self.device_name = config.get('customer_display_device_name',
                                   self._connect_port())
     self.device_rate = int(config.get('customer_display_device_rate',
                                       9600))
     self.device_timeout = int(
         config.get('customer_display_device_timeout', 2))
     self.serial = False
예제 #21
0
 def _get_cypher(cls, private=False):
     symmetric_key = config.get(CONFIG_KEYCHAIN_KEY)
     private_key = config.get(CONFIG_KEYCHAIN_PRIVATE_KEY)
     public_key = config.get(CONFIG_KEYCHAIN_PUBLIC_KEY)
     cypher = cls._get_symmetric_cypher
     args = (symmetric_key, )
     if public_key or private_key:
         if symmetric_key:
             _logger.warn("Both symmetric key and asymmetric keys are set, "
                          "defaulting to asymmetric encryption")
         cypher = cls._get_asymmetric_cypher
         args = (private_key, public_key, private)
     return cypher(*args)
 def __init__(self, mysql_host='mysql_host', mysql_user='******',
              mysql_pw='mysql_pw', mysql_db='mysql_db'):
     """Establishes the connection to the MySQL server used."""
     mh = config.get(mysql_host)
     mu = config.get(mysql_user)
     mp = config.get(mysql_pw)
     md = config.get(mysql_db)
     self._con = False
     try:
         self._con = MySQLdb.connect(mh, mu, mp, md, charset='utf8')
         self._cur = self._con.cursor(MySQLdb.cursors.DictCursor)
     except MySQLdb.Error, e:
         logger.debug("Error %d: %s" % (e.args[0], e.args[1]))
 def __init__(self, mysql_host='mysql_host', mysql_user='******',
              mysql_pw='mysql_pw', mysql_db='mysql_db'):
     """Establishes the connection to the MySQL server used."""
     mh = config.get(mysql_host)
     mu = config.get(mysql_user)
     mp = config.get(mysql_pw)
     md = config.get(mysql_db)
     self._con = False
     try:
         self._con = mdb.connect(mh, mu, mp,
                                 md, charset='utf8')
         self._cur = self._con.cursor(mdb.cursors.DictCursor)
     except mdb.Error, e:
         logger.debug("Error %d: %s" % (e.args[0], e.args[1]))
예제 #24
0
    def _monitoring_info(cls, request, response, begin, end):
        if isinstance(response, HTTPException):
            status_code = response.code
        else:
            status_code = response.status_code
        info = {
            # timing
            "start_time": time.strftime("%Y-%m-%d %H:%M:%S",
                                        time.gmtime(begin)),
            "duration": end - begin,
            # HTTP things
            "method": request.httprequest.method,
            "url": request.httprequest.url,
            "status_code": status_code,
            "headers": request.httprequest.environ.copy(),
            # Odoo things
            "uid": request.uid,
            "server_environment": config.get("running_env"),
        }
        if hasattr(request, "session"):
            info["session"] = dict(request.session)
        if hasattr(request, "params"):
            info["params"] = dict(request.params)

        return info
예제 #25
0
    def update_templates(self):
        api_key = config.get('sendgrid_api_key')
        if not api_key:
            raise exceptions.UserError(
                _('Missing sendgrid_api_key in conf file'))

        sg = sendgrid.SendGridAPIClient(apikey=api_key)
        template_client = sg.client.templates
        msg = template_client.get().body
        result = json.loads(msg)

        for template in result.get("templates", list()):
            id = template["id"]
            msg = template_client._(id).get().body
            template_versions = json.loads(msg)['versions']
            for version in template_versions:
                if version['active']:
                    template_vals = version
                    break
            else:
                continue

            vals = {
                "remote_id": id,
                "name": template["name"],
                "html_content": template_vals["html_content"],
                "plain_content": template_vals["plain_content"],
            }
            record = self.search([('remote_id', '=', id)])
            if record:
                record.write(vals)
            else:
                self.create(vals)
        return True
예제 #26
0
 def _auth_method_oauth2_app(cls):
     client_id = cls._oauth_validation()
     # For mobile app, we check that the token was requested from us,
     # using the GMC connect client
     authorized_client = config.get('connect_client', 'admin')
     if client_id != authorized_client:
         raise Unauthorized()
    def _get_sendgrid(self):
        api_key = config.get('sendgrid_api_key')
        if not api_key:
            raise UserError(_('ConfigError'),
                            _('Missing sendgrid_api_key in conf file'))

        return SendGridAPIClient(apikey=api_key)
예제 #28
0
    def upload(self, remove_local_data_file=True, overwrite=True):
        for record in self:
            try:
                file_full_path = os.path.join(config.get('data_dir'),
                                              record.file)
                if not os.path.exists(file_full_path):
                    _logger.error(
                        "Cannot find file ({}), thus not uploading".format(
                            file_full_path))
                    continue

                blob = BlobClient(account_url=record.storage_account_url,
                                  container_name=record.container,
                                  blob_name=record.blob_name,
                                  credential=record.credential)

                try:
                    record._do_upload(blob, file_full_path)
                except ResourceExistsError as ex:
                    if not overwrite:
                        _logger.info(
                            "El fichero existe, no sd sobreescribe por que overwrite=False"
                        )
                        continue
                    _logger.debug("El fichero existe, hay que sobreescribirlo")
                    blob.delete_blob()
                    _logger.debug(
                        "El fichero se ha borrado para sobreescribirlo")
                    record._do_upload(blob, file_full_path)

                if remove_local_data_file: os.unlink(file_full_path)
            except Exception as ex:
                _logger.error("Error uploading to Blob: type({}), {}".format(
                    type(ex), ex))
                continue
예제 #29
0
 def _get_extra_environment_info_div(self, current_env, extra_envs):
     # TODO we could use a qweb template here
     button_div = "<div>"
     button_string = _("Define values for ")
     for environment in extra_envs:
         button = """
         <button name="action_change_env_data_encrypted_fields"
                 type="object" string="{}{}"
                 class="btn btn-lg btn-primary ml-2"
                 context="{}"/>
         """.format(button_string, environment,
                    {"environment": environment})
         button_div += "{}".format(button)
     button_div += "</div>"
     alert_string = _("Modify values for {} environment").format(
         current_env)
     alert_type = (current_env == config.get("running_env") and "alert-info"
                   or "alert-warning")
     elem = etree.fromstring("""
           <div class="d-flex justify-content-between">
           <div class="alert lead {} text-center d-inline">
               <strong>{}</strong>
             </div>
             {}
           </div>
     """.format(alert_type, alert_string, button_div))
     return elem
예제 #30
0
    def setUp(self):
        super(TestKeychain, self).setUp()

        self.keychain = self.env['keychain.account']
        config['keychain_key'] = Fernet.generate_key()

        self.old_running_env = config.get('running_env', '')
        config['running_env'] = None

        def _init_data(self):
            return {
                "c": True,
                "a": "b",
                "d": "",
            }

        def _validate_data(self, data):
            return 'c' in data

        keychain_clss = self.keychain.__class__
        keychain_clss._keychain_test_init_data = _init_data
        keychain_clss._keychain_test_validate_data = _validate_data

        self.keychain._fields['namespace'].selection.append(
            ('keychain_test', 'test'))
예제 #31
0
    def setUp(self):
        super().setUp()

        self.encrypted_data = self.env['encrypted.data']
        self.set_new_key_env('test')
        self.old_running_env = config.get('running_env', '')
        config['running_env'] = 'test'
        self.crypted_data_name = 'test_model,1'
    def _get_sendgrid(self):
        api_key = config.get('sendgrid_api_key')
        if not api_key:
            raise UserError(
                _('ConfigError'),
                _('Missing sendgrid_api_key in conf file'))

        return SendGridAPIClient(apikey=api_key)
 def __new__(cls):
     """ Inherit method to ensure a single instance exists. """
     if TestOnrampConnector.__instance is None:
         TestOnrampConnector.__instance = object.__new__(cls)
         connect_url = config.get('connect_url')
         api_key = config.get('connect_api_key')
         if connect_url and api_key:
             TestOnrampConnector.__instance._connect_url = connect_url
             TestOnrampConnector.__instance._api_key = api_key
             session = requests.Session()
             session.params.update({'api_key': api_key})
             TestOnrampConnector.__instance._session = session
         else:
             raise UserError(
                 _('Please give connect_url and connect_api_key values '
                   'in your Odoo configuration file.'))
     return TestOnrampConnector.__instance
예제 #34
0
 def __new__(cls):
     """ Inherit method to ensure a single instance exists. """
     if OnrampConnector.__instance is None:
         OnrampConnector.__instance = object.__new__(cls)
         connect_url = config.get("connect_url")
         api_key = config.get("connect_api_key")
         if connect_url and api_key:
             OnrampConnector.__instance._connect_url = connect_url
             OnrampConnector.__instance._api_key = api_key
             session = requests.Session()
             session.params.update({"api_key": api_key, "gpid": "CH"})
             OnrampConnector.__instance._session = session
         else:
             raise UserError(
                 _("Please give connect_url and connect_api_key values "
                   "in your Odoo configuration file."))
     return OnrampConnector.__instance
예제 #35
0
def _load_running_env():
    if not system_base_config.get("running_env"):
        _logger.warning("`running_env` not found. Using default = `test`.")
        _logger.warning(
            "We strongly recommend against using the rc file but instead use an "
            "explicit config file or env variable.")
        # safe default
        system_base_config["running_env"] = "test"
예제 #36
0
 def __new__(cls):
     """ Inherit method to ensure a single instance exists. """
     if OnrampConnector.__instance is None:
         OnrampConnector.__instance = object.__new__(cls)
         connect_url = config.get('connect_url')
         api_key = config.get('connect_api_key')
         if connect_url and api_key:
             OnrampConnector.__instance._connect_url = connect_url
             OnrampConnector.__instance._api_key = api_key
             session = requests.Session()
             session.params.update({'api_key': api_key, 'gpid': 'CH'})
             OnrampConnector.__instance._session = session
         else:
             raise UserError(
                 _('Please give connect_url and connect_api_key values '
                   'in your Odoo configuration file.'))
     return OnrampConnector.__instance
예제 #37
0
 def test_config_set(self):
     """Test that the config is properly set on the server.
     """
     url = config.get('middleware_url')
     self.assertTrue(url)
    def import_web_letter(self, child_code, sponsor_ref, name, email,
                          original_text, template_name, pdf_filename,
                          attachment_filename, ext, utm_source, utm_medium,
                          utm_campaign):
        """
        Call when a letter is set on web site:
            - add web letter to an import set with import letter config
              'Web letter'
        """
        try:
            # Find existing config or create a new one
            web_letter_id = self.env.ref('sbc_switzerland.web_letter').id
            import_config = self.search([
                ('config_id', '=', web_letter_id),
                ('state', '!=', 'done')], limit=1)
            if not import_config:
                import_config = self.create({
                    'config_id': web_letter_id, 'state': 'open'})

            # Retrieve child code and find corresponding id
            child_field = 'local_id'
            if len(child_code) == 9:
                child_field = 'code'
            model_child = self.env['compassion.child'].search(
                [(child_field, '=', child_code)])

            child_id = model_child.id

            # Retrieve sponsor reference and find corresponding id
            model_sponsor = self.env['res.partner'].search(
                ['|', ('ref', '=', sponsor_ref),
                 ('global_id', '=', sponsor_ref)])
            if not model_sponsor:
                model_sponsor = model_sponsor.search([('email', '=', email)])
            if len(model_sponsor) > 1:
                model_sponsor = model_sponsor.filtered('has_sponsorships')
            sponsor_id = model_sponsor[:1].id

            lang = self.env['correspondence'].detect_lang(original_text)
            lang_id = lang and lang.id

            # Retrieve template name and find corresponding id
            template = self.env['correspondence.template'].search(
                [('name', '=', template_name)], limit=1)

            # save_letter pdf
            sftp_host = config.get('wp_sftp_host')
            sftp_user = config.get('wp_sftp_user')
            sftp_pw = config.get('wp_sftp_pwd')
            sftp = pysftp.Connection(sftp_host, sftp_user, password=sftp_pw)
            pdf_data = sftp.open(pdf_filename).read()
            filename = 'WEB_' + sponsor_ref + '_' + \
                child_code + '_' + str(time.time())[:10] + '.pdf'

            pdf_letter = self.analyze_webletter(pdf_data)

            # analyze attachment to check template and create image preview
            line_vals = func.analyze_attachment(
                self.env, pdf_letter, filename, template)

            # Check UTM
            internet_id = self.env.ref('utm.utm_medium_website').id
            utms = self.env['utm.mixin'].get_utms(
                utm_source, utm_medium, utm_campaign)

            for i in xrange(0, len(line_vals)):
                line_vals[i].update({
                    'import_id': import_config.id,
                    'partner_id': sponsor_id,
                    'child_id': child_id,
                    'letter_language_id': lang_id,
                    'original_text': original_text,
                    'source': 'website',
                    'source_id': utms['source'],
                    'medium_id': utms.get('medium', internet_id),
                    'campaign_id': utms['campaign'],
                    'email': email,
                    'partner_name': name
                })
                self.env['import.letter.line'].create(line_vals[i])

            import_config.import_completed = True
            logger.info("Try to copy file {} !".format(filename))
            # Copy file in attachment in the done letter folder
            share_nas = self.env.ref('sbc_switzerland.share_on_nas').value
            import_letter_path = self.env.ref(
                'sbc_switzerland.scan_letter_imported').value + filename

            file_pdf = BytesIO(pdf_letter)
            smb_conn = self._get_smb_connection()
            if smb_conn and smb_conn.connect(
                    SmbConfig.smb_ip, SmbConfig.smb_port):
                smb_conn.storeFile(share_nas, import_letter_path, file_pdf)

                # save eventual attachment
                if attachment_filename:
                    attachment_data = sftp.open(attachment_filename).read()
                    filename_attachment = filename.replace(".pdf", "." + ext)
                    logger.info("Try save attachment {} !"
                                .format(filename_attachment))

                    import_letter_path = self.env.ref(
                        'sbc_switzerland.scan_letter_imported').value + \
                        filename_attachment

                    file_attachment = BytesIO(attachment_data)
                    smb_conn.storeFile(
                        share_nas,
                        import_letter_path,
                        file_attachment)
                smb_conn.close()
            sftp.close()

            # Accept privacy statement
            model_sponsor[:1].set_privacy_statement(
                origin='new_letter')

            return True
        except:
            logger.error("Failed to create webletter", exc_info=True)
            return False