Files
Python_Examples/stm_etl/FTP/mg_810.py
T

280 lines
10 KiB
Python

'''
Created on Jul 15, 2015
@author: Wes
'''
from alert import send_alert_html
from glob import glob
import os, sys, logging, time, StringIO
import pyodbc
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy.sql.expression import update
RECIPIENTS = ['admin@example.com']
SUBJECT = 'Invoices Transmitted to Momentum.'
MESSAGE = None
TEST_MODE = False
LOG_LEVEL = logging.DEBUG
ACC_NUMBERS = ['3398', '4318', '5230', '6600', '4063']
engine = create_engine("mssql+pyodbc://@jsisbprod", echo=False)
Base = declarative_base(engine)
metadata = Base.metadata
logger = None
########################################################################
# Jomar Invoice (EDI 810) staging tables #
########################################################################
class CSPINV00(Base):
__tablename__ = 'CSPINV00'
__table_args__ = {'autoload':True}
class CSPINV01(Base):
__tablename__ = 'CSPINV01'
__table_args__ = {'autoload':True}
class TransactionTable(Base):
__tablename__ = 'ftp_trans_numbers'
__table_args__ = {'autoload':True}
########################################################################
# Jomar Item description tables. Used to look up Pattern name, color, #
# style, etc. for a given item number #
########################################################################
class TXMYAT03(Base):
__tablename__ = 'TXMYAT03'
__table_args__ = {'autoload':True}
########################################################################
# Jomar Customer master file. Used to look up account names #
########################################################################
class CustomerMaster(Base):
__tablename__ = 'TXUYKD00'
__table_args__ = {'autoload':True}
def loadSession():
global engine
Session = sessionmaker(bind=engine)
session = Session()
return session
def initializeLogger(name='log'):
global logger
global MESSAGE
#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)
#Capture log messages in a string for e-mail alert
MESSAGE = StringIO.StringIO()
sh = logging.StreamHandler(MESSAGE)
sh.setLevel(logging.DEBUG)
sh.setFormatter(formatter)
logger.addHandler(sh)
'''
Gotta get transaction number from AS400 until ALL transmissions
are handled on the new system... whoopee
'''
def getTransNumber():
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
c1.execute('select * from stmdata.MGTX#FL')
for row in c1:
ret = int(row[1]) + 1
c1.close()
return ret
'''
Update the Momentum transaction number in the AS400 database
'''
def updateTransNumber(txnum):
connection = pyodbc.connect(
driver='{iSeries Access ODBC Driver}',
system='SUNBURY',
uid=os.environ['AS400_UID'],
pwd=os.environ['AS400_PWD'],
autocommit=True)
c1 = connection.cursor()
c1.execute('UPDATE STMDATA.MGTX#FL SET MGSEQ# = ' + str(txnum))
c1.close()
'''
Grabs any unprocessed Maharam invoices from the 810 EDI staging tables in Jomar.
Formats data into text document to send to Maharam via FTP.
Marks invoices as processed.
'''
def createMomentumInvoiceDocument():
global MESSAGE
initializeLogger('MOM_810_GENERATE')
xmission = [] #List of strings, the individual lines of the transmission file that will be sent
invoices_to_flag_processed = []
#First line of transmission is T or P. 'Test' or 'Production'
if(TEST_MODE):
logger.info('**RUNNING IN TEST MODE**')
xmission.append('T~\n')
else:
logger.info('**RUNNING IN PRODUCTION MODE**')
xmission.append('P~\n')
logger.debug('Connecting to database...')
session = loadSession()
trans_no = -1
# t = session.query(mf_transaction_number).filter(mf_transaction_number.doc == '810')
# if t.count() == 1:
# for row in t:
# trans_no = row.txnum
# else:
# logger.fatal('Failed to retrieve transaction number from database... Something ain\'t right. %s', t.count())
# sys.exit('Failed to retrieve transaction number from database... Something ain\'t right.')
trans_no = getTransNumber()
#Second line (Control Line) of transmission is essentially a boilerplate
logger.info('Building Control Line')
ctrlLine = 'TP~12~5702863800~12~9498338886~'
ctrlLine += time.strftime('%Y%m%d')
ctrlLine += '~' + str(trans_no)
xmission.append(ctrlLine + "\n")
logger.debug(ctrlLine)
logger.info('Querying EDI table for unprocessed invoices...')
logger.debug('SELECT * FROM CSPINV00 WHERE IVCUSTB IN (\'3398\', \'4318\', \'5230\', \'6600\') ORDER BY IVIDAT;')
q = session.query(CSPINV00,CustomerMaster).order_by(CSPINV00.IVIDAT).filter(CSPINV00.IVCUSTB.in_(ACC_NUMBERS)).filter(CustomerMaster.KKDN == CSPINV00.IVCUSTB)
for row in q:
if(row[0].IVPROCSS == 'Y'):
continue
invoices_to_flag_processed.append(row[0].IVINV)
businessGroup = row[0].IVBNR
plant = row[0].IVPLT
invoiceType = row[0].IVITYP
logger.info('Building header line for invoice: ' + row[0].IVINV)
#Translate Sunbury bill-to account number to Momentum vendor number
momVendor = ''
if(row[0].IVCUSTB == '3398'):
momVendor = '6975'
elif(row[0].IVCUSTB == '4318'):
momVendor = '0036'
elif(row[0].IVCUSTB == '5230'):
momVendor = '7738'
elif(row[0].IVCUSTB == '6600'):
momVendor = '2082'
elif(row[0].IVCUSTB == '4063'):
momVendor = '2082'
logger.debug('Sunbury Account: %s --> Momentum Vendor: %s', row[0].IVCUSTB, momVendor)
momPO = row[0].IVCPO[-5:]
hLine = 'H~'
hLine += (row[0].IVINV + '~')
hLine += (str(row[0].IVIDAT) + '~')
hLine += (momVendor + '~')
hLine += (momPO + '~')
hLine += (row[0].IVCUSTB + '~')
#hLine += (row[0].IVTERMS + '~')
hLine += ('02~') #Changed to constant '02' per Kim Stolmeier @ Momentum
hLine += (row[1].KNA2 + '~')
hLine += (row[0].IVSADD1 + '~')
hLine += (row[0].IVSCTY + '~')
hLine += (row[0].IVSST + '~')
hLine += (row[0].IVSZIP + '~')
hLine += (row[1].KNA2 + '~')
hLine += (row[0].IVBADD1 + '~')
hLine += (row[0].IVBCTY + '~')
hLine += (row[0].IVBST + '~')
hLine += (row[0].IVBZIP + '~')
hLine += (str(row[0].IVFRT) + '~')
xmission.append(hLine + "\n")
logger.debug(hLine)
logger.info('Querying EDI table for invoice detail lines for invoice: ' + row[0].IVINV)
logger.debug('SELECT * FROM CSPINV01 LEFT JOIN TXMYAT03 ON TXMYAT03.XANR = CSPINV01.I1ITEM WHERE CSPINV01.I1BNR = \'' + businessGroup + '\' AND CSPINV01.I1PLT = \'' + plant + '\' AND CSPINV01.I1ITYP = \'' + invoiceType + '\' AND CSPINV01.I1INV = \'' + row[0].IVINV + '\';')
q2 = session.query(CSPINV01).filter(CSPINV01.I1BNR == businessGroup, CSPINV01.I1PLT == plant, CSPINV01.I1ITYP == invoiceType, CSPINV01.I1INV == row[0].IVINV).join(TXMYAT03, TXMYAT03.XANR == CSPINV01.I1ITEM).add_entity(TXMYAT03)
for row2 in q2:
if(row2[0].I1ITEM == 'INSURANCE'):
'''
@todo: Does Momentum even pay for insurance?
'''
logger.warn('Skipping insurance line!')
continue
logger.info('Building detail line for line ' + str(row2[0].I1ILINE))
dLine = 'D~'
dLine += (row2[1].XFLX33 + '~')
dLine += (row2[1].XFLX34 + '~')
dLine += (row2[1].XFLX35 + '~')
dLine += ("{0:.3f}".format(row2[0].I1QTY) + '~')
dLine += ("{0:.2f}".format(row2[0].I1PRI) + '~')
dLine += (momPO + '~')
xmission.append(dLine + "\n")
logger.debug(dLine)
if len(xmission) > 2:
xmission.append('S~' + str(len(xmission)) + '~')
#Write transmission data out to file here
logger.info('Creating D:\\FTP\\SEND_MG\\SBR_810_' + str(trans_no) + '.txt')
f = open('SEND_MG\\SBR_810_' + str(trans_no) + '.txt', 'w')
f.writelines(xmission)
f.close()
try:
logger.info('Sending e-mail alert...')
send_alert_html(RECIPIENTS, SUBJECT, attachments=glob('D:\\FTP\\SEND_MG\\SBR_810_*.txt'), message=MESSAGE.getvalue())
except:
logger.error('Unable to send e-mail. Is the internet out?')
#Update EDI tables and transaction number #mf_transaction_number
if(len(invoices_to_flag_processed) > 0 and not TEST_MODE):
#Set process flag on these invoices to 'Y'
ex = update(CSPINV00.__table__).where(CSPINV00.IVINV.in_(invoices_to_flag_processed)).values(IVPROCSS=u"Y")
session.execute(ex)
ex = None
#Might as well keep the table in the new database up to date
ex2 = update(TransactionTable.__table__).where(TransactionTable.client.in_(['MOMTEX'])).values(xaction=(trans_no))
session.execute(ex2)
ex2 = None
logger.debug('Comitting changes to database...')
session.commit()
updateTransNumber(trans_no) #Update transaction number in AS400
logger.debug('Closing database connection...')
session.close()
else:
logger.warn('Nothing to send!')
session.close()
MESSAGE.truncate(0)
if __name__ == '__main__':
createMomentumInvoiceDocument()