File: D:/bin/scripts/python3.4/expressmusic/expressmusic_stock_update - Copy (3).py
# (SS,27/08/15) Python script to update Express Music stock levels from separate MySQL databased called seanic
# Version of Python must be 3.4 or greater
# (SS,12/12/25) Added def is_stock_update_exclusion_date() which looks at "Stock Update Exclusion Dates" token in sitedetails
# This allows Express Music to modify the exclusion dates
import datetime
import mysql.connector
import sys
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import email.utils
def do_stock_update():
# get the source records
LSQL = """SELECT Stock_Levels.System_Code, SUM(Stock_Level - Allocated) AS StockLevel, RRP
FROM Stock_Levels
INNER JOIN Product ON Product.System_Code = Stock_Levels.System_Code
GROUP BY System_Code"""
cursor_source.execute(LSQL)
# empty the existing destination table
cursor_destin.execute("TRUNCATE TABLE seanic_stock_levels")
# copy the records from source to destination
for row in cursor_source.fetchall():
LSQL = "INSERT INTO seanic_stock_levels VALUES " + str(tuple(row));
cursor_destin.execute(LSQL)
# update the stocks levels in products table if different to seanic and product isn't disabled
LSQL = """UPDATE products p, seanic_stock_levels s
SET p.NumInStock = s.Stock_Level
WHERE s.System_Code = p.ProductCode AND
NOT p.ProductDisabled AND p.NumInStock <> s.Stock_Level"""
cursor_destin.execute(LSQL)
print_log("Product records updated: " + str(cursor_destin.rowcount))
# count products where prices don't match seanic
LSQL = """SELECT COUNT(*) FROM products p
INNER JOIN seanic_stock_levels s ON s.System_Code = p.ProductCode
WHERE NOT p.ProductDisabled AND p.StdPrice <> s.RRP AND COALESCE(p.SalePrice, 0) <> s.RRP"""
cursor_destin.execute(LSQL)
result = cursor_destin.fetchone()
print_log("Product records with different prices: " + str(result[0]))
def set_alert(AAlert):
global FAlert # required to modify a global
FAlert = AAlert
def get_alert():
return FAlert
def print_log(AText):
global FPrintLog # required to modify a global
print(AText)
FPrintLog = FPrintLog + AText + '\r\n'
def send_email_text(ABody, ASubject, AFrom, ATo, ABcc):
# Create a text/plain message
msg = MIMEText(ABody)
# 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'
# send the messsage using localhost
s = smtplib.SMTP('localhost')
s.sendmail(AFrom, [ATo, ABcc], msg.as_string())
s.quit()
# (SS,12/12/2025) created by Google Gemini 3 Pro (Thinking) using my instructions
def is_stock_update_exclusion_date():
"""
Checks if today is a stock update exclusion date based on rules
stored in the 'Stock Update Exclusion Dates' token.
Logs setup and results to print_log.
"""
global cursor_destin
# Assuming print_log is available in the global scope
try:
# 1. Get the text from the database
query = 'SELECT Text FROM sitedetails WHERE Type = "Tokens" AND Name = "Stock Update Exclusion Dates"'
cursor_destin.execute(query)
result = cursor_destin.fetchone()
if not result or result[0] is None:
print_log("Stock Update Exclusion: No token found. Proceeding with update.")
return False
token_text = result[0]
# 2. Parse the text to list active rules (ignoring comments/blanks)
lines = token_text.splitlines()
active_rules = []
for line in lines:
clean_line = line.strip()
# Skip empty lines and comments
if clean_line and not clean_line.startswith("#"):
active_rules.append(clean_line)
# Log the configured rules
print_log(f"Stock Update Exclusion Rules Loaded: {', '.join(active_rules)}")
# 3. Get current date information
now = datetime.datetime.now()
current_day_name = now.strftime("%A") # e.g., "Monday"
current_date_str = now.strftime("%d/%m/%Y") # e.g., "25/12/2025"
# Log today's parameters
print_log(f"Stock Update Exclusion Check: Today is {current_day_name}, {current_date_str}")
# 4. Check for matches
for rule in active_rules:
# Check Day of Week (case-insensitive)
if rule.lower() == current_day_name.lower():
print_log(f"Stock Update Exclusion Match: Today is '{rule}'. Update Excluded.")
return True
# Check Specific Date
if rule == current_date_str:
print_log(f"Stock Update Exclusion Match: Today is '{rule}'. Update Excluded.")
return True
# If we get here, no exclusions matched
print_log("Stock Update Exclusion: No exclusion found. Update Allowed.")
return False
except Exception as e:
# Pass the exception object to your logging function
print_log(e)
# Default to False (allow update) so the process doesn't break silently
return False
FAlert = False # global used to set alert
FPrintLog = "" # global used to hold log that is also the email body
start = datetime.datetime.now()
print_log('Started: ' + start.strftime('%Y-%m-%d %H:%M:%S'))
print_log('')
try:
# source connection
cnx_source = None
cursor_source = None
# destination connection
cnx_destin = None
cursor_destin = None
print("1")
# open destination connection
# replaced localhost with 127.0.0.1
cnx_destin = mysql.connector.connect(user='expressmusic', password='bsharp',
host='127.0.0.1',
database='expressmusic')
print("1.5")
cursor_destin = cnx_destin.cursor()
print("2")
# (SS,12/12/25) added following to check for dates to exclude and only run if today is not excluded
if not is_stock_update_exclusion_date():
# open source connection seanic database
cnx_source = mysql.connector.connect(user='elvis_presley', password='Su5p1ci0u5',
host='data.seanicretail.co.uk',
database='Express_Music')
cursor_source = cnx_source.cursor()
print("4")
do_stock_update();
except:
set_alert(True)
print_log("Error:")
print_log(str(sys.exc_info()))
#raise
finally:
# close connections if they were opened
if cursor_destin:
cursor_destin.close()
if cnx_destin:
cnx_destin.commit()
cnx_destin.close()
if cursor_source:
cursor_source.close()
if cnx_source:
cnx_source.close()
finish = datetime.datetime.now()
time_taken = finish - start
print_log('')
print_log('Finished: ' + finish.strftime('%Y-%m-%d %H:%M:%S'))
print_log('Time taken: %0.3f seconds' % (time_taken.seconds + time_taken.microseconds / 1E6))
# send the text as an email, from address stock-update@expressmusicstore.co.uk doesn't actually exist as valid mailbox
send_email_text(FPrintLog, 'Express Music Stock Level Update Result', 'stock-update@expressmusicstore.co.uk', 'surinder@itpartnership.com', '')