HEX
Server: Microsoft-IIS/10.0
System: Windows NT ITPWINWEBSVR22 10.0 build 20348 (Windows Server 2022) AMD64
User: www.conferencesearch.co.uk (0)
PHP: 8.3.30
Disabled: NONE
Upload Files
File: D:/bin/scripts/python/test.py
# (SS,07/04/14) Python script to lookup EUR and USD exchanges rates from Yahoo and save to HyperFlight currency tables
# (SS,28/04/14) Added comparison tables
# (SS,03/11/15) Modified to also save exchange rates to hypercomposites
# (SS,06/06/16) change emails to go to neil@hyperflight.co.uk instead of sales@hy
# (SS,25/11/16) had stopped working on 22/10/2016 due to password change, modified password from b747 to b747A380
# (SS,19/01/17) had stopped working slowly since 3/12/2016, completely on 11/1/2017, fixed by change to get_currency_yahoo 
# (SS,19/01/17) change to def get_comparisons to ignore currencies not in currencies table and order list using sort order field from currencies table
# (SS,19/01/17) changed sort order of call to get_currency to use the SortOrder field of the currencies table
# (SS,13/02/17) change to def get_currency_yahoo, because it had stopped working again, modifiying "data-reactid" from 250 to 244 was enough to fix it.
# (SS,07/03/17) change to def get_currency_yahoo, because it had stopped working again, modifiying "data-reactid" from 244 to 240 was enough to fix it.
# (SS,29/03/17) change to def get_currency_yahoo, because it had stopped working again, modifiying "data-reactid" from 240 to 243 was enough to fix it.
# (SS,03/05/17) change to def get_currency_yahoo, because it had stopped working again, modifiying "data-reactid" from 243 to 36 was enough to fix it.
# (SS,28/07/17) change to def get_currency_yahoo, because it had stopped working again, modified {"data-reactid" : "36"} to {"data-reactid" : "35"} 36 was causing picking up different section: ValueError: invalid literal for float(): -0.0015 (-0.1321%)
# (SS,31/07/17) above didn't work. Change to work in a different way. Now using what looks like JSON values contained in the HTML. Search for e.g. "currency":"EUR","regularMarketPrice"
# (SS,25/01/18) change to def get_currency to also save ExchangeRateDate, i.e. the date without time for faster query joins
# (SS,23/02/18) added import json, also modified to use European Central Bank via http://fixer.io because Yahoo not working correctly
# (SS,06/04/18) had stopped working on 29/3/18. Due to change by Fixer. Error alert was working well, email was alert but kept showing log from 28/3/18. Improved error handling and fixed by registering for free access. Had to use the access key provided. Base currency is now EUR, had to adjust to GBP in get_currency_ecb
# (SS,04/06/18) changed password for HyperFlight and removed HyperComposites.
# (SS,23/06/19) Replaced localhost with 127.0.0.1 for MySQL connection to overcome IPv6 issue with localhost not connecting due to it trying ::1 instead of 127.0.0.1
# (SS,11/11/22) made compatible with Python 3 (3.11), added brackets () around multiple exceptions, and print commands, changed to use different mysql connector, replaced 127.0.0.1 with localhost, fixed HTML email issue, also URL library

#import urllib2
# (SS,11/11/22) replaced above with following
from urllib.request import urlopen

import datetime

# from BeautifulSoup import BeautifulSoup
# (SS,11/11/22) replaced above with following
from bs4 import BeautifulSoup

# import MySQLdb
# (SS,11/11/22) replaced above with following
import mysql.connector

import sys
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import email.utils
import json

def fetch_page(AURL): 
  print_html(AURL)
  
  req = urllib2.Request(AURL, '',  {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.3; WOW64)'})
  response = urllib2.urlopen(req)
  the_page = response.read()  
  
  return the_page      

# (SS,31/7/17) version 1 used prior to 31/7/17
def get_currency_yahoo_v1(AFromCurrency, AToCurrency):
    LToken = AFromCurrency.lower() + AToCurrency.lower() # e.g. gbpusd
    LURL = 'http://uk.finance.yahoo.com/q?s=' + LToken + '=x'
    html = fetch_page(LURL)
    
    soup = BeautifulSoup(html)
    
    # find the exchange rate which is in a span e.g. <span id="yfs_l10_gbpusd=x">1.6592</span>
    #spans = soup.findAll('span', {"id" : "yfs_l10_" + LToken + "=x"})
    # (SS,19/1/17) it had stopped working due to site change, replaced above with following to fix, don't know how long it'll work for
    # (SS,13/2/17) stopped working again on 8/2/17. Noticed that data-reactid was now 244, i.e. <span class="Fw(b) Fz(36px) Mb(-4px) D(ib)" data-reactid="244">1.2569</span>
    # modified following from {"data-reactid" : "250"} to {"data-reactid" : "244"}
    # (SS,7/3/17) modified following from {"data-reactid" : "244"} to {"data-reactid" : "240"}
    # (SS,29/3/17) modified following from {"data-reactid" : "240"} to {"data-reactid" : "243"}
    # (SS,3/5/17) modified following from {"data-reactid" : "243"} to {"data-reactid" : "36"}
    # (SS,28/5/17) modified following from {"data-reactid" : "36"} to {"data-reactid" : "35"} 36 was causing picking up different section: ValueError: invalid literal for float(): -0.0015 (-0.1321%)
    spans = soup.findAll('span', {"data-reactid" : "35"})
    LExchangeRate = 0
    
    if len(spans) > 0:
        try:
            # (SS,19/11/15) added .replace(',','') to remove commas, comma was causing error for KRW which was > 1,771
            LExchangeRate = float(spans[0].text.strip().replace(',',''))
        except (ValueError, e):
            print_html('ValueError: %s' % (e))
    else:
        print_html('Exchange rate not found')
        
    return LExchangeRate
    
# (SS,31/7/17) new version used after 31/7/17
def get_currency_yahoo(AFromCurrency, AToCurrency):
    #e.g. https://uk.finance.yahoo.com/quote/GBPUSD=x
    LURL = 'http://uk.finance.yahoo.com/quote/' + AFromCurrency + AToCurrency + '=x'
    html = fetch_page(LURL)        
    
    LExchangeRate = 0
    LExchangeRateStr = ""
    
    # look for e.g. "currency":"EUR","regularMarketPrice":{"raw":1.1175889,"fmt":"1.1176"},
    LFoundPos = html.find('"currency":"' + AToCurrency + '","regularMarketPrice":')    
    
    # look for float after "fmt" and put in string
    if LFoundPos > -1:
      LFoundPos = html.find('"fmt"', LFoundPos)
      if LFoundPos > -1:
        i = LFoundPos + len('"fmt"') + 2
        while True:
          c = html[i]
          if c == '"':
            break
          else:
            LExchangeRateStr = LExchangeRateStr + c
          i = i + 1
    
    if FDebugMode:
      print_html(AToCurrency + ': ' + LExchangeRateStr)
        
    if LFoundPos > -1:
        try:
            # (SS,19/11/15) added .replace(',','') to remove commas, comma was causing error for KRW which was > 1,771, strip removes leading and trailing spaces
            LExchangeRate = round(float(LExchangeRateStr.strip().replace(',','')), 4)
        except (ValueError, e):
            print_html('ValueError: %s' % (e))
    else:
        print_html('Exchange rate not found')
        
    return LExchangeRate 

# (SS,23/2/18) get the currency exchange rates from European Central Bank via http://fixer.io/ and https://api.fixer.io
# store in to global currency_data
def get_currencies_from_ecb():
  global currency_data
  
  # url = 'https://api.fixer.io/latest?base=GBP'
  # (SS,6/4/18) replaced above with following becauce it had stopped working, had to register for free access, the base currency is now EUR, they charge $10 per month for other base currencies
  url = 'http://data.fixer.io/api/latest?access_key=6bf429bf5cc1c4945ae071238f7f078c'
  
  # (SS,6/4/18) added following
  print_html("Fetching from: " + url)
  
  # response = urllib2.urlopen(url)
  # currency_data = json.loads(response.read())
  # (SS,11/11/22) replaced above with following
  currency_data = json.loads(urlopen(url).read())
  
  #print(currency_data['rates']["USD"])
  #print(currency_data['rates']["GBP"])
  #print(currency_data)

# (SS23/2/18) get the required value from currency_data, base of GBP is assumed. 0 is returned if error occurred
def get_currency_ecb(AFromCurrency, AToCurrency):
  
  try:
    # (SS,6/4/18) base is now EUR, they charge $10 extra for other base currencies, added code to factor using EUR to GBP to convert to GBP base currency
    LEUR_to_GBP = float(currency_data['rates']['GBP'])
    LExchangeRate = float(currency_data['rates'][AToCurrency])
    LExchangeRate = LExchangeRate / LEUR_to_GBP
  except: # catch *all* exceptions
    print_html("Error: " + str(sys.exc_info()[0]))
    set_alert(True)    
    LExchangeRate = 0
  return LExchangeRate
   
# (SS,23/2/18) added APreviousExchangeRate to allow for variation check
def get_currency(AFromCurrency, AToCurrency, APreviousExchangeRate):
    print_html("")
    # LExchangeRate = get_currency_yahoo(AFromCurrency, AToCurrency)
    # (SS,23/2/18) replaced get_currency_yahoo with get_currency_ecb
    LExchangeRate = get_currency_ecb(AFromCurrency, AToCurrency)
    
    print_html('Exchange rate %s to %s: %s' % (AFromCurrency, AToCurrency, LExchangeRate))
    # (SS,23/2/18) added following to show the previous rate and difference
    print_html('Previous rate %s' % (APreviousExchangeRate))
    LDifference = round((LExchangeRate - APreviousExchangeRate) / APreviousExchangeRate * 100, 2)
    print_html('Difference is %s' % (LDifference) + '%')
    # (SS,23/2/18) added following to alert if >= 5%
    if abs(LDifference) >= 5:
      set_alert(True)
      print_html('<strong>Alert! Difference greater than 5%</strong>')
    
    # save in history table
	# (SS,25/1/18) added ExchangeRateDate to speed up a query in reports for historical currency lookup
    LSQL = 'INSERT INTO currency_history SET \
        ExchangeRateDateTime = NOW(), ExchangeRateDate = CURDATE(), Currency = "%s", \
        ExchangeRate = %0.4f' % (AToCurrency, LExchangeRate)
    cur.execute(LSQL)
    
    # update currencies table if <> 0
    if LExchangeRate != 0:
        LSQL = 'UPDATE currencies SET \
            ExchangeRate = %0.4f \
            WHERE Currency = "%s"' % (LExchangeRate, AToCurrency)
        cur.execute(LSQL)
        # (SS,3/11/15) do the same in hypercomposites
        # (SS,4/6/18) removed hypercomposites
        #cur_hypercomposites.execute(LSQL)
    else:
        set_alert(True) # signal alert if exchange is 0

def set_alert(AAlert):
    global FAlert # required to modify a global 
    FAlert = AAlert
    # (SS,2/4/18) added following to debug why alert is being set
    # (SS,6/4/18) removed following, the issue was caused previous log being emailed, and error was occurring earlier
    # print_html('Alert set to: ' + str(FAlert))
      
def get_alert():
    return FAlert

# (SS,26/4/14)    
# (SS,19/1/17) modified to only include currencies in the currencies table, it was including HKD which had been removed some time ago. So changed to use the sort order from currencies table
def get_comparisons():
    LSQL = """\
CREATE TEMPORARY TABLE tmp_exchange_rates

SELECT Currency, "0D" AS PastPeriod, ExchangeRate FROM currency_history
WHERE ExchangeRate <> 0 AND DATE(ExchangeRateDateTime) = DATE_SUB(CURDATE(), INTERVAL 0 DAY)

UNION ALL

SELECT Currency, "1D" AS PastPeriod, ExchangeRate FROM currency_history
WHERE ExchangeRate <> 0 AND DATE(ExchangeRateDateTime) = DATE_SUB(CURDATE(), INTERVAL 1 DAY)

UNION ALL

SELECT Currency, "1W" AS PastPeriod, ExchangeRate FROM currency_history
WHERE ExchangeRate <> 0 AND DATE(ExchangeRateDateTime) = DATE_SUB(CURDATE(), INTERVAL 1 WEEK)

UNION ALL

SELECT Currency, "2W" AS PastPeriod, ExchangeRate FROM currency_history
WHERE ExchangeRate <> 0 AND DATE(ExchangeRateDateTime) = DATE_SUB(CURDATE(), INTERVAL 2 WEEK)

UNION ALL

SELECT Currency, "3W" AS PastPeriod, ExchangeRate FROM currency_history
WHERE ExchangeRate <> 0 AND DATE(ExchangeRateDateTime) = DATE_SUB(CURDATE(), INTERVAL 3 WEEK)

UNION ALL

SELECT Currency, "1M" AS PastPeriod, ExchangeRate FROM currency_history
WHERE ExchangeRate <> 0 AND DATE(ExchangeRateDateTime) = DATE_SUB(CURDATE(), INTERVAL 1 MONTH)

UNION ALL

SELECT Currency, "2M" AS PastPeriod, ExchangeRate FROM currency_history
WHERE ExchangeRate <> 0 AND DATE(ExchangeRateDateTime) = DATE_SUB(CURDATE(), INTERVAL 2 MONTH)

UNION ALL

SELECT Currency, "3M" AS PastPeriod, ExchangeRate FROM currency_history
WHERE ExchangeRate <> 0 AND DATE(ExchangeRateDateTime) = DATE_SUB(CURDATE(), INTERVAL 3 MONTH)

UNION ALL

SELECT Currency, "6M" AS PastPeriod, ExchangeRate FROM currency_history
WHERE ExchangeRate <> 0 AND DATE(ExchangeRateDateTime) = DATE_SUB(CURDATE(), INTERVAL 6 MONTH)

UNION ALL

SELECT Currency, "1Y" AS PastPeriod, ExchangeRate FROM currency_history
WHERE ExchangeRate <> 0 AND DATE(ExchangeRateDateTime) = DATE_SUB(CURDATE(), INTERVAL 1 YEAR)

UNION ALL

SELECT Currency, "2Y" AS PastPeriod, ExchangeRate FROM currency_history
WHERE ExchangeRate <> 0 AND DATE(ExchangeRateDateTime) = DATE_SUB(CURDATE(), INTERVAL 2 YEAR)

UNION ALL

SELECT Currency, "3Y" AS PastPeriod, ExchangeRate FROM currency_history
WHERE ExchangeRate <> 0 AND DATE(ExchangeRateDateTime) = DATE_SUB(CURDATE(), INTERVAL 3 YEAR)

UNION ALL

SELECT Currency, "4Y" AS PastPeriod, ExchangeRate FROM currency_history
WHERE ExchangeRate <> 0 AND DATE(ExchangeRateDateTime) = DATE_SUB(CURDATE(), INTERVAL 4 YEAR)

UNION ALL

SELECT Currency, "5Y" AS PastPeriod, ExchangeRate FROM currency_history
WHERE ExchangeRate <> 0 AND DATE(ExchangeRateDateTime) = DATE_SUB(CURDATE(), INTERVAL 5 YEAR)

UNION ALL

SELECT Currency, "6Y" AS PastPeriod, ExchangeRate FROM currency_history
WHERE ExchangeRate <> 0 AND DATE(ExchangeRateDateTime) = DATE_SUB(CURDATE(), INTERVAL 6 YEAR)

UNION ALL

SELECT Currency, "7Y" AS PastPeriod, ExchangeRate FROM currency_history
WHERE ExchangeRate <> 0 AND DATE(ExchangeRateDateTime) = DATE_SUB(CURDATE(), INTERVAL 7 YEAR)

UNION ALL

SELECT Currency, "8Y" AS PastPeriod, ExchangeRate FROM currency_history
WHERE ExchangeRate <> 0 AND DATE(ExchangeRateDateTime) = DATE_SUB(CURDATE(), INTERVAL 8 YEAR)

UNION ALL

SELECT Currency, "9Y" AS PastPeriod, ExchangeRate FROM currency_history
WHERE ExchangeRate <> 0 AND DATE(ExchangeRateDateTime) = DATE_SUB(CURDATE(), INTERVAL 9 YEAR)

UNION ALL

SELECT Currency, "10Y" AS PastPeriod, ExchangeRate FROM currency_history
WHERE ExchangeRate <> 0 AND DATE(ExchangeRateDateTime) = DATE_SUB(CURDATE(), INTERVAL 10 YEAR)

UNION ALL

SELECT Currency, "11Y" AS PastPeriod, ExchangeRate FROM currency_history
WHERE ExchangeRate <> 0 AND DATE(ExchangeRateDateTime) = DATE_SUB(CURDATE(), INTERVAL 11 YEAR)

UNION ALL

SELECT Currency, "12Y" AS PastPeriod, ExchangeRate FROM currency_history
WHERE ExchangeRate <> 0 AND DATE(ExchangeRateDateTime) = DATE_SUB(CURDATE(), INTERVAL 12 YEAR)

UNION ALL

SELECT Currency, "13Y" AS PastPeriod, ExchangeRate FROM currency_history
WHERE ExchangeRate <> 0 AND DATE(ExchangeRateDateTime) = DATE_SUB(CURDATE(), INTERVAL 13 YEAR)

UNION ALL

SELECT Currency, "14Y" AS PastPeriod, ExchangeRate FROM currency_history
WHERE ExchangeRate <> 0 AND DATE(ExchangeRateDateTime) = DATE_SUB(CURDATE(), INTERVAL 14 YEAR)

UNION ALL

SELECT Currency, "15Y" AS PastPeriod, ExchangeRate FROM currency_history
WHERE ExchangeRate <> 0 AND DATE(ExchangeRateDateTime) = DATE_SUB(CURDATE(), INTERVAL 15 YEAR)

"""

    cur.execute(LSQL)
    
    LSQL = """\
SELECT c.Currency, c.ExchangeRate,
AVG(IF(PastPeriod = "1D", t.ExchangeRate, NULL)) AS OneDay,
AVG(IF(PastPeriod = "1W", t.ExchangeRate, NULL)) AS OneWeek,
AVG(IF(PastPeriod = "2W", t.ExchangeRate, NULL)) AS TwoWeeks,
AVG(IF(PastPeriod = "3W", t.ExchangeRate, NULL)) AS ThreeWeeks,
AVG(IF(PastPeriod = "1M", t.ExchangeRate, NULL)) AS OneMonth,
AVG(IF(PastPeriod = "2M", t.ExchangeRate, NULL)) AS TwoMonths,
AVG(IF(PastPeriod = "3M", t.ExchangeRate, NULL)) AS ThreeMonths,
AVG(IF(PastPeriod = "6M", t.ExchangeRate, NULL)) AS SixMonths,
AVG(IF(PastPeriod = "1Y", t.ExchangeRate, NULL)) AS OneYear,
AVG(IF(PastPeriod = "2Y", t.ExchangeRate, NULL)) AS TwoYears,
AVG(IF(PastPeriod = "3Y", t.ExchangeRate, NULL)) AS ThreeYears,
AVG(IF(PastPeriod = "4Y", t.ExchangeRate, NULL)) AS FourYears,
AVG(IF(PastPeriod = "5Y", t.ExchangeRate, NULL)) AS FiveYears,
AVG(IF(PastPeriod = "6Y", t.ExchangeRate, NULL)) AS SixYears,
AVG(IF(PastPeriod = "7Y", t.ExchangeRate, NULL)) AS SevenYears,
AVG(IF(PastPeriod = "8Y", t.ExchangeRate, NULL)) AS EightYears,
AVG(IF(PastPeriod = "9Y", t.ExchangeRate, NULL)) AS NineYears,
AVG(IF(PastPeriod = "10Y", t.ExchangeRate, NULL)) AS TenYears,
AVG(IF(PastPeriod = "11Y", t.ExchangeRate, NULL)) AS ElevenYears,
AVG(IF(PastPeriod = "12Y", t.ExchangeRate, NULL)) AS TwelveYears,
AVG(IF(PastPeriod = "13Y", t.ExchangeRate, NULL)) AS ThirteenYears,
AVG(IF(PastPeriod = "14Y", t.ExchangeRate, NULL)) AS FourteenYears,
AVG(IF(PastPeriod = "15Y", t.ExchangeRate, NULL)) AS FifteenYears
FROM tmp_exchange_rates t
INNER JOIN currencies c ON c.Currency = t.Currency
WHERE c.Currency <> "GBP"
GROUP BY Currency
ORDER BY c.SortOrder IS NULL, c.SortOrder, c.Currency
"""
     
    cur.execute(LSQL)
    rows = cur.fetchall()     
    
    for type in range(0, 3):    
      print('<table>')
      print('<tr>')
      print('<th>Code</th><th>Rate</th><th>1D</th><th>1W</th><th>2W</th><th>3W</th><th>1M</th><th>2M</th><th>3M</th><th>6M</th><th>1Y</th><th>2Y</th><th>3Y</th><th>4Y</th><th>5Y</th><th>6Y</th><th>7Y</th><th>8Y</th><th>9Y</th><th>10Y</th><th>11Y</th><th>12Y</th><th>13Y</th><th>14Y</th><th>15Y</th>')
      print('</tr>')
      for row in rows:
        #    get_currency('GBP', row[0]) # e.g. get_currency('GBP', 'EUR')
        #get_currency('GBP', 'EUR')
        print('<tr style="text-align:right">')
        for f in range(0, 25):
          if f == 0:
            print('<td style="text-align:left"><a href="http://uk.finance.yahoo.com/q?s=gbp%s=x">%s</a></td>' % (row[f].lower(), row[f]))
          else:
            if row[f] == None:
              print('<td></td>')
            else:
              if f >= 2:
                if type == 0:
                  print('<td>%.4f</td>' % (row[f]))
                elif type == 1:
                  print('<td>%+.4f</td>' % (row[1] - row[f]))
                else: # i.e. 2
                  print('<td>%+.2f%%</td>' % ((row[1] - row[f]) / row[1] * 100))
              else:
                print('<td>%s</td>' % row[f])
        print('</tr>')
      print('</table>')
      print('<br>')


def print_html_header():
      print("""<html>
<title>HyperFlight Order</title>
<style>
html, body, h1, h2, p {
  font-family: Arial, Helvetica, sans-serif;
}
img {
  border: 0;
}
table {
  border-collapse: collapse;
}
table, th, td {
  border: 1px solid black;
}
td, th {
  padding: 5px;
  white-space: nowrap;
}
</style>
<body>
""")

def print_html_footer():
    print("""</body>
</html>""")

def print_html(AText):
    print(AText + "<br>")
    
    

# (SS,6/4/18) simple HTML escape, from https://wiki.python.org/moin/EscapingHtml 
def html_escape(text):
  html_escape_table = {
      "&": "&amp;",
       '"': "&quot;",
       "'": "&apos;",
       ">": "&gt;",
       "<": "&lt;",
       }
  """Produce entities within text."""
  return "".join(html_escape_table.get(c,c) for c in text)    
      
def send_email_file(AFileName, ASubject, AFrom, ATo, ABcc):
  # Open a plain text file for reading.  For this example, assume that
  # the text file contains only ASCII characters.
  fp = open(AFileName, 'rb')
  # Create a text/plain message
  #msg = MIMEText(fp.read())
  html = fp.read()
  fp.close()
  
  msg = MIMEMultipart('alternative')

  # header    
  if get_alert():
      msg['Subject'] = 'ALERT!!! ' + ASubject
  else:
      msg['Subject'] = ASubject
  msg['From'] = AFrom
  msg['To'] = ATo
  msg['Date'] = email.utils.formatdate(localtime=True)
  if get_alert():       
      msg['X-Priority'] = '2'  
  
  #* html = html.replace('\r\n', '<br>')
  # (SS,11/11/22) added following to fix error in Python 3: AttributeError: 'bytes' object has no attribute 'encode'
  html = html.decode("utf-8")  
  
  part1 = MIMEText(html, 'html')
  msg.attach(part1)
          
  # send the messsage using localhost
  s = smtplib.SMTP('localhost')
  s.sendmail(AFrom, [ATo, ABcc], msg.as_string())
  s.quit()
     
    
# (SS,23/2/18) added following try to catch all errors and make sure email is sent   
try:
     
  LOG_FILE = 'get_currency_exchange_rates.log'

  FAlert = False  # global used to set alert

  # (SS,31/7/17) added following for enter into debug mode, i.e. email not sent, info displayed on screen, certain things not rung
  FDebugMode = False # True 
      
  # output all prints to file
  f = open(LOG_FILE, 'w')
  if not FDebugMode:
    sys.stdout = f 
        
  start = datetime.datetime.now()
  print_html_header()
  print_html('Started: ' + start.strftime('%Y-%m-%d %H:%M:%S'))
  filename_date_suffix = start.strftime('%Y-%m-%d')

  # (SS,23/2/18) now getting all currencies in one go from XML file on European Central Bank website, via http://fixer.io/
  # (SS,6/4/18) moved here from above f = open, because when failing it wasn't sending the correct error message in the email, it was sending the previous log
  get_currencies_from_ecb()
  # exit
  #sys.exit(0) 

  # (SS,25/11/16) had stopped working on 22/10/2016 due to password change, modified password from  b747 to b747A380
  # (SS,4/6/18) changed password to b747A380 to blasTsniP749#
  # (SS,23/6/19) replaced localhost with 127.0.0.1 due to IPv6 issue and not connected to IPv4
  # (SS,11/11/22) replaced MySQLdb with mysql.connector, and 127.0.0.1 with localhost
  con = mysql.connector.connect(host='localhost', user='hyperflight', passwd='blasTsniP749#', db='hyperflight')
  cur = con.cursor()

  # (SS,3/11/15) added following to update the exchange rates in hypercomposites
  # (SS,4/6/18) removed hypercomposites
  #con_hypercomposites = MySQLdb.connect(host='localhost', user='hypercomposites', passwd='b787', db='hypercomposites')
  # (SS,4/6/18) removed hypercomposites
  #cur_hypercomposites = con_hypercomposites.cursor()

  # fetch all (non GBP) currencies from currencies table
  # (SS,19/1/17) changed order from ORDER BY Currency to ORDER BY SortOrder IS NULL, SortOrder, Currency
  # (SS,23/2/18) added ExchangeRate, and extra parameter to get_currency, to allow a percentage difference sanity check
  cur.execute("SELECT Currency, ExchangeRate FROM currencies WHERE Currency <> 'GBP' ORDER BY SortOrder IS NULL, SortOrder, Currency")
  rows = cur.fetchall()
  for row in rows:
    # e.g. get_currency('GBP', 'EUR')
    # (SS,23/2/18) added row[1] for current ExchangeRate
    get_currency('GBP', row[0], float(row[1])) 
    # (31/7/17) only one iteration if in debug mode
    #if FDebugMode:
    #  break
    
  #get_currency('GBP', 'EUR')

  finish = datetime.datetime.now()
  time_taken = finish - start
  print_html('')
  print_html('Finished: ' + finish.strftime('%Y-%m-%d %H:%M:%S'))
  print_html('Time taken: %0.3f seconds' % (time_taken.seconds + time_taken.microseconds / 1E6))

  print_html('')

  # (SS,26/4/14)
  # (SS,31/7/17) only do if not in debug mode
  if not FDebugMode:
      get_comparisons()

  # (SS,3/11/15)
  # (SS,4/6/18) removed hypercomposites
  #cur_hypercomposites.close()
  #con_hypercomposites.close()

  cur.close()
  con.close()


  
except: # catch *all* exceptions
  #print(sys.exc_info()[0])
  #print_html('3')
  #print_html("Error: " + str(sys.exc_info()[0]))
  print_html("Error: " + html_escape(str(sys.exc_info()[0])))
  set_alert(True)  
  

# (SS,6/4/18) moved following here from just before except, required to show error in except correctly formatted, otherwise email shows blank
finish = datetime.datetime.now()
time_taken = finish - start
#print_html('')
print_html('Finished: ' + finish.strftime('%Y-%m-%d %H:%M:%S'))
print_html('Time taken: %0.3f seconds' % (time_taken.seconds + time_taken.microseconds / 1E6))
print_html_footer()
# set back to default out and close the opened log file
if not FDebugMode:
  sys.stdout = sys.__stdout__
f.close()  
  

# send the file as an email
#send_email_file(LOG_FILE, 'HyperFlight Exchange Rate Result', 'exchange_rate@hyperflight.co.uk', 'surinder@itpartnership.com', 'surinder@ssbsoft.co.uk')
# (SS,6/6/16) changed sales@hyperflight.co.uk to neil@hyperflight.co.uk due to Help Scout being used for sales@ and we don't these notification emails to clog up Help Scout
#send_email_file(LOG_FILE, 'HyperFlight Exchange Rate Result', 'exchange_rate@hyperflight.co.uk', 'neil@hyperflight.co.uk', 'contactforms@itpartnership.com')
# (SS,31/7/17) only send email if not in debug mode
if not FDebugMode:
  send_email_file(LOG_FILE, 'HyperFlight Exchange Rate Result', 'exchange_rate@hyperflight.co.uk', 'surinder@itpartnership.com', 'surinder@ssbsoft.co.uk')
  #send_email_file(LOG_FILE, 'HyperFlight Exchange Rate Result', 'exchange_rate@hyperflight.co.uk', 'neil@hyperflight.co.uk', 'contactforms@itpartnership.com')