Files
Python_Examples/stm_etl/FTP/dt_cut.py
T

233 lines
8.6 KiB
Python

'''
Create and send e-mail alert listing Designtex pieces that need to be invoiced.
'''
import logging, os, pyodbc, sys
from alert import send_alert_html
from sqlalchemy import create_engine, or_
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy.sql.expression import update
RECIPIENTS = ['admin@example.com', 'user3@example.com', 'user4@example.com', 'user1@example.com', 'user5@example.com']
#RECIPIENTS = ['admin@example.com']
SUBJECT = 'Designtex Reconciliation Report'
TEST_MODE = False
LOG_LEVEL = logging.DEBUG
ROLL_NUM = 1
JOMAR_LINE = 3
ITEM_NUM = 4
AS400_LINE = 5
PATTERN = 6
COLOR = 7
PACKING_LIST = 8
engine = create_engine("mssql+pyodbc://jsisbprod", echo=False)
#engine = create_engine("mssql+pyodbc://JTest", echo=False)
Base = declarative_base(engine)
metadata = Base.metadata
class DTXCUTFL(Base): #EDI data from Designtex arrives here
__tablename__ = 'DTXCUTFL'
__table_args__ = {'autoload':True}
class TXRYRT00(Base): #Roll/Tag Master (ticketfl)
__tablename__ = 'TXRYRT00'
__table_args__ = {'autoload':True}
class TXUYUV00(Base): #Order header
__tablename__ = 'TXUYUV00'
__table_args__ = {'autoload':True}
class TXUYUF01(Base): #Order detail
__tablename__ = 'TXUYUF01'
__table_args__ = {'autoload':True}
class TXMYAT03(Base): #Sales item detail
__tablename__ = 'TXMYAT03'
__table_args__ = {'autoload':True}
class AS400OrderLookupError(RuntimeError):
''' Raised if we fail to lookup the AS400 order number using the Jomar order number. '''
''' This will eventually go away '''
class JomarOrderLookupError(RuntimeError):
''' Raised if we fail to lookup the Jomar order number using the AS400 order number '''
''' This will eventually go away '''
class AS400LineLookupError(RuntimeError):
''' Raised if AS400 line numbers cannot be retrieved from the Jomar order '''
''' This will eventually go away '''
class RollNotFoundError(RuntimeError):
''' Raised if no record in TXRYRT00 is found for a given ticket number '''
class ItemLookupError(RuntimeError):
''' Raised if no record is found in TXMYAT03 for a given item number '''
''' This should never happen '''
def loadSession():
global engine
Session = sessionmaker(bind=engine)
session = Session()
return session
def initializeLogger(name='log'):
global logger
#logger = logging.getLogger(__name__)
logger = logging.getLogger(name)
if len(logger.handlers) > 0:
return logger
logger.setLevel(LOG_LEVEL)
handler = logging.FileHandler('D:\\FTP\\logs\\' + name + '.log')
handler.setLevel(LOG_LEVEL)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
#Also send logs > DEBUG to stdout
ch = logging.StreamHandler(sys.stdout)
ch.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter)
logger.addHandler(ch)
def getAS400PackingList(order, line, ticket):
global logger
connection = pyodbc.connect(
driver='{iSeries Access ODBC Driver}',
system='SUNBURY',
uid=os.environ['AS400_UID'],
pwd=os.environ['AS400_PWD'])
c1 = connection.cursor()
ret = -1
q = "select SHP# from stmdata.XSHPFIL WHERE ORDERA = '"
q = q + order + "' and LINE# = "
q = q + line + " and TICK# = "
q = q + ticket
logger.debug(q)
c1.execute(q)
for row in c1:
ret = row[0]
c1.close()
return str(ret)
def dtxInvoiceAlert():
initializeLogger('dtx_cut_alert')
session = loadSession()
processed_records = []
logger.info('Querying DTXCUTFL for any unprocessed rolls...')
tickets = session.query(DTXCUTFL).filter(or_(DTXCUTFL.PROCESSED != 'Y', DTXCUTFL.PROCESSED == None))
#Load in unprocessed roll/order numers
for row in tickets:
processed_records.append([row.__dict__['STM_ORDER#'], row.__dict__['STM_TICK#']])
if len(processed_records) == 0:
logger.warn('Nothing to process. Exiting...')
return
#Fix/lookup Order Numbers
logger.info('Querying order header table for order numbers...')
for row in processed_records:
#Not sure whether they are transmitting new or old style order numbers, allow for both.
if(row[0].startswith('U')):
row.append(row[0]) #We want U number to be 3rd column
oHeader = session.query(TXUYUV00).filter(TXUYUV00.URBPO == row[0], TXUYUV00.UBLA == 'SO')
if oHeader.count() != 1:
raise JomarOrderLookupError('Failed to lookup Jomar order number. AS400 Order:', row[0])
for r in oHeader:
logger.debug('AS400 Order: %s --> Jomar Order: %s', row[0], r.UBLN)
row[0] = r.UBLN #Overwrite contents of first element with Jomar Order
else:
oHeader = session.query(TXUYUV00).filter(TXUYUV00.UBLN == row[0])
if oHeader.count() != 1:
raise AS400OrderLookupError('Failed to lookup AS400 order number. Jomar Order:', row[0])
for r in oHeader:
logger.debug('Jomar Order: %s --> AS400 Order: %s', row[0], r.URBPO)
row.append(r.URBPO)
logger.debug('*')
logger.info('Querying roll/tag master for order line numbers and SKUs...')
for row in processed_records:
rtMaster = session.query(TXRYRT00).filter(TXRYRT00.RTBNR == '001', TXRYRT00.RTRNR == row[ROLL_NUM])
if rtMaster.count() != 1:
raise RollNotFoundError('Roll does not exist in Jomar!', row[ROLL_NUM])
for r in rtMaster:
logger.debug('Roll: %s --> Line: %s SKU: %s', row[ROLL_NUM], r.RTAFN, r.RTANR)
row.append(str(r.RTAFN))
row.append(r.RTANR)
logger.debug('*')
logger.info('Querying order detail table for AS400 Line numbers...')
for row in processed_records:
oDetail = session.query(TXUYUF01).filter(TXUYUF01.VBLA == 'SO', TXUYUF01.VBLN == row[0], TXUYUF01.VBNR == '001', TXUYUF01.VLFN == row[JOMAR_LINE], TXUYUF01.VPLT == '00')
if oDetail.count() != 1:
raise AS400LineLookupError('Failed to retrieve AS400 line number.', row[0], row[JOMAR_LINE])
for r in oDetail:
logger.debug('Jomar Order: %s Line: %s --> AS400 Line: %s', row[0], row[JOMAR_LINE], r.VPLIN)
row.append(str(r.VPLIN))
logger.debug('*')
logger.info('Querying sales item info table for STM pattern and color...')
for row in processed_records:
itemDetail = session.query(TXMYAT03).filter(TXMYAT03.XANR == row[ITEM_NUM], TXMYAT03.XBNR == '001', TXMYAT03.XPLT == '00')
if itemDetail.count() != 1:
raise ItemLookupError('Sales item lookup failed? I don\'t even know...', row[ITEM_NUM])
for r in itemDetail:
logger.debug('Jomar Item: %s --> %s-%s', row[ITEM_NUM], r.XFLX33, r.XFLX34)
row.append(r.XFLX33)
row.append(r.XFLX34)
logger.debug('*')
logger.info('Querying XSHPFIL on the AS400 to get packing list numbers...')
for row in processed_records:
row.append(getAS400PackingList(row[2], row[AS400_LINE], row[ROLL_NUM]))
logger.debug('*')
#Build e-mail message
msg = 'Designtex has cut into the following pieces:<br><br>'
msg = msg + '<table border="1">'
msg = msg + '<tr>'
msg = msg + '<th>Roll #</th>'
msg = msg + '<th>AS400 Packing List</th>'
msg = msg + '<th>Jomar Order</th>'
msg = msg + '<th>Pattern</th>'
msg = msg + '<th>Color</th>'
msg = msg + '</tr>'
for row in processed_records:
msg = msg + '<tr>'
msg = msg + '<td>' + row[ROLL_NUM] + '</td>'
msg = msg + '<td>' + row[PACKING_LIST] + '</td>'
msg = msg + '<td>' + row[0] + '</td>'
msg = msg + '<td>' + row[PATTERN] + '</td>'
msg = msg + '<td>' + row[COLOR] + '</td>'
msg = msg + '</tr>'
msg = msg + '</table>'
logger.info('Sending e-mails...')
send_alert_html(RECIPIENTS, SUBJECT, message=msg)
p = [row[ROLL_NUM].strip() for row in processed_records]
if(len(p) > 0 and not TEST_MODE):
logger.info('Marking records processed in database...')
flag = 'UPDATE DTXCUTFL SET PROCESSED = \'Y\' where STM_TICK# in ' + str(p).replace('[', '(').replace(']', ')')
session.execute(flag)
session.commit()
if __name__ == '__main__':
#getAS400PackingList('U58475', '1', '52828') #Test packing number retrieval from AS400
dtxInvoiceAlert()