253 lines
10 KiB
Python
253 lines
10 KiB
Python
'''
|
|
Created on May 12, 2015
|
|
|
|
NOTE: A _packing list_ triggers a new header record in this transmission not a shipment. There can
|
|
and often will be more header records in a transmission file than there were shipments.
|
|
|
|
@author: Wes
|
|
'''
|
|
from alert import send_alert_html
|
|
from glob import glob
|
|
|
|
import datetime, logging, os, sys, pyodbc, StringIO
|
|
|
|
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 = 'Shipment Notices Transmitted to Momentum.'
|
|
MESSAGE = None
|
|
|
|
TEST_MODE = False
|
|
LOG_LEVEL = logging.DEBUG
|
|
ACC_NUMBERS = ['3398', '4318', '5230']
|
|
|
|
engine = create_engine("mssql+pyodbc://jsisbprod", echo=False)
|
|
Base = declarative_base(engine)
|
|
metadata = Base.metadata
|
|
|
|
class CSPASN00(Base):
|
|
__tablename__ = 'CSPASN00'
|
|
__table_args__ = {'autoload':True}
|
|
class CSPASN01(Base):
|
|
__tablename__ = 'CSPASN01'
|
|
__table_args__ = {'autoload':True}
|
|
class CSPASN02(Base):
|
|
__tablename__ = 'CSPASN02'
|
|
__table_args__ = {'autoload':True}
|
|
class CSPASN03(Base):
|
|
__tablename__ = 'CSPASN03'
|
|
__table_args__ = {'autoload':True}
|
|
class CSPASN04(Base):
|
|
__tablename__ = 'CSPASN04'
|
|
__table_args__ = {'autoload':True}
|
|
class XREF(Base): #Customer Xref Table
|
|
__tablename__ = 'TXUYAT01'
|
|
__table_args__ = {'autoload':True}
|
|
class TXRYRT00(Base): #Roll/Tag Master (ticketfl)
|
|
__tablename__ = 'TXRYRT00'
|
|
__table_args__ = {'autoload':True}
|
|
class TXMYAT03(Base):
|
|
__tablename__ = 'TXMYAT03'
|
|
__table_args__ = {'autoload':True}
|
|
class TXRYPS00(Base):
|
|
__tablename__ = 'TXRYPS00'
|
|
__table_args__ = {'autoload':True}
|
|
class TransactionTable(Base):
|
|
__tablename__ = 'ftp_trans_numbers'
|
|
__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()
|
|
|
|
def createMomentumASN():
|
|
global MESSAGE
|
|
initializeLogger('MOM_856_GENERATE')
|
|
session = loadSession()
|
|
shipments_to_flag_processed = []
|
|
lines = []
|
|
trans_no = getTransNumber()
|
|
|
|
logger.info('Querying CSPASN0[0,1] for unprocessed shipments...')
|
|
shipmentQ = session.query(CSPASN00,CSPASN01).order_by(CSPASN00.MSTBIL).filter(CSPASN00.CUSTNO.in_(ACC_NUMBERS)).filter(CSPASN00.ABNR == CSPASN01.ABNR, CSPASN00.APLT == CSPASN01.APLT, CSPASN00.CUSTNO == CSPASN01.CUSTNO, CSPASN00.MSTBIL == CSPASN01.MSTBIL)
|
|
for shipment in shipmentQ:
|
|
if(shipment[0].PROCSS == 'Y'):
|
|
continue
|
|
|
|
#lines = []
|
|
|
|
bGroup = shipment[0].ABNR
|
|
plant = shipment[0].APLT
|
|
cust = shipment[0].CUSTNO
|
|
shipmentNumber = shipment[0].MSTBIL
|
|
shipmentDate = datetime.datetime.strptime(str(shipment[1].SHPDTE), "%Y%m%d")
|
|
|
|
logger.info('Processing shipment number: ' + shipmentNumber)
|
|
logger.info(' Shipped on: ' + shipmentDate.strftime('%m/%d/%Y'))
|
|
shipments_to_flag_processed.append(shipmentNumber)
|
|
|
|
logger.info('Querying CSPASN02 for packing lists on this shipment...')
|
|
packingListQ = session.query(CSPASN02).order_by(CSPASN02.BOLNUM).filter(CSPASN02.ABNR == bGroup, CSPASN02.APLT == plant, CSPASN02.CUSTNO == cust, CSPASN02.MSTBIL == shipmentNumber)
|
|
for packingList in packingListQ:
|
|
plNumber = packingList.BOLNUM
|
|
poNumber = packingList.PONUM
|
|
stmOrder = packingList.ORDNUM
|
|
|
|
#Build Header Record of transmission
|
|
hRec = 'H~%s~%s~%s~%s~%s~%s~%s\n' % (plNumber, '', '', shipmentDate.strftime('%m/%d/%Y'), '', poNumber, '')
|
|
lines.append(hRec)
|
|
|
|
detailQ = session.query(CSPASN03,CSPASN04,TXRYPS00,XREF,TXRYRT00).order_by(CSPASN04.LINE).filter(CSPASN03.ABNR == CSPASN04.ABNR, CSPASN03.APLT == CSPASN04.APLT, CSPASN03.CUSTNO == CSPASN04.CUSTNO,
|
|
CSPASN03.MSTBIL == CSPASN04.MSTBIL, CSPASN03.BOLNUM == CSPASN04.BOLNUM, CSPASN03.CTN == CSPASN04.CTN).filter(CSPASN03.ABNR == bGroup, CSPASN03.APLT == plant,
|
|
CSPASN03.CUSTNO == cust, CSPASN03.MSTBIL == shipmentNumber, CSPASN03.BOLNUM == plNumber).filter(CSPASN04.ABNR == TXRYPS00.PSBNR,
|
|
CSPASN04.APLT == TXRYPS00.PSPLT, CSPASN04.CUSTNO == TXRYPS00.PSKDN, CSPASN04.SB_PATTERNAME == TXRYPS00.PSPRT,
|
|
CSPASN04.SB_COLORNUM == TXRYPS00.PSANR).filter(CSPASN04.ABNR == XREF.UACBNR, CSPASN04.APLT == XREF.UACPLT, CSPASN04.CUSTNO == XREF.UACCNR,
|
|
CSPASN04.ITEM == XREF.UACANR).filter(CSPASN04.ABNR == TXRYRT00.RTBNR, CSPASN04.APLT == TXRYRT00.RTPLT, CSPASN04.ITEM == TXRYRT00.RTANR,
|
|
CSPASN04.ROLNUM == TXRYRT00.RTRNR)
|
|
detailCount = detailQ.count()
|
|
for detail in detailQ:
|
|
poLine = detail[1].LINE
|
|
momStyle = detail[3].UACPAT
|
|
momColor = detail[3].UACCOL
|
|
momProductNum = detail[2].PSFD01[:8] #Momentum product numbers are always 8 digits, it seems like we've left padded them with too many zeros in our DB
|
|
ydsShipped = "{0:.3f}".format(detail[1].SQTY)
|
|
weight = "{0:.1f}".format(detail[4].RTSWG)
|
|
pieceNum = detail[1].ROLNUM
|
|
ourPattern = detail[1].SB_PATTERNAME.strip()
|
|
ourColor = detail[1].SB_COLORNUM.strip()
|
|
|
|
dRec = 'D~%s~%s~%s~%s~%s~%s~%s~%s~%s~%s\n' % (momProductNum, momStyle, momColor, '', ydsShipped, 'YD', pieceNum, '', weight, 'LB')
|
|
|
|
# @todo: There is a bug in the nightmare of a query above that was causing duplicate rows
|
|
# to be created in the tranmission for seemingly random rolls. In every case I've found
|
|
# the lines that make it into the transmission are identical. So the below 'fix' is good
|
|
# enough to get us off the ground for the time being.
|
|
#
|
|
# 07/11/2016 - I believe this is fixed now by adding "CSPASN03.CTN == CSPASN04.CTN" to the first
|
|
# .filter() clause for the 03 <-> 04 join. I discovered this while working on
|
|
# Maharam's 856 document. Need to verify...
|
|
if not lines[-1].split('~')[7] == pieceNum:
|
|
lines.append(dRec)
|
|
else:
|
|
logger.warn('Query still messed up...')
|
|
|
|
tRec = 'T~' + str(detailCount) + "\n"
|
|
lines.append(tRec)
|
|
|
|
sRec = 'S~' + str(len(lines)) #+ "\n"
|
|
lines.append(sRec)
|
|
|
|
if(len(shipments_to_flag_processed) > 0):
|
|
#Write transmission data out to file here
|
|
logger.info('Creating D:\\FTP\\SEND_MG\\SBR_856_' + str(trans_no) + '.txt')
|
|
f = open('D:\\FTP\\SEND_MG\\SBR_856_' + str(trans_no) + '.txt', 'w')
|
|
f.writelines(lines)
|
|
f.close()
|
|
|
|
try:
|
|
logger.info('Sending e-mail alert...')
|
|
send_alert_html(RECIPIENTS, SUBJECT, attachments=glob('D:\\FTP\\SEND_MG\\SBR_856_*.txt'), message=MESSAGE.getvalue())
|
|
except:
|
|
logger.error('Unable to send e-mail. Is the internet out?')
|
|
|
|
if not TEST_MODE:
|
|
#Mark shipments as processed
|
|
ex = update(CSPASN00.__table__).where(CSPASN00.MSTBIL.in_(shipments_to_flag_processed)).values(PROCSS=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
|
|
|
|
|
|
if(len(shipments_to_flag_processed) == 0):
|
|
logger.info('Nothing to send!')
|
|
|
|
logger.debug('Closing database connection...')
|
|
session.close()
|
|
|
|
MESSAGE.truncate(0)
|
|
|
|
'''
|
|
00 - List of shipments
|
|
01 - Contains shipment date for shipments in 01
|
|
02 - List of packing slips on each shipment
|
|
'''
|
|
if __name__ == '__main__':
|
|
createMomentumASN()
|