Initial commit. Loads XLSX file from accounting into sqlite database. Sends HTML email. Started adding variable parts to body pulled from database.
This commit is contained in:
97
InvoiceDatabase.py
Normal file
97
InvoiceDatabase.py
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
from openpyxl import load_workbook
|
||||||
|
from sqlalchemy import create_engine, Column, Integer, String, REAL
|
||||||
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
|
||||||
|
engine = create_engine('sqlite:///cffInvoice.db')
|
||||||
|
engine.connect()
|
||||||
|
Base = declarative_base()
|
||||||
|
|
||||||
|
|
||||||
|
class Invoice(Base):
|
||||||
|
__tablename__ = 'Invoice'
|
||||||
|
rowid = Column(Integer, primary_key=True, autoincrement=True)
|
||||||
|
OrderID = Column(String)
|
||||||
|
InvoiceNumber = Column(String)
|
||||||
|
DateCreated = Column(String)
|
||||||
|
ProductionCharges = Column(REAL)
|
||||||
|
ShippingCharges = Column(REAL)
|
||||||
|
AdjustmentsBalance = Column(REAL)
|
||||||
|
DuePayment = Column(REAL)
|
||||||
|
ChargeCode = Column(String)
|
||||||
|
UserLogon = Column(String)
|
||||||
|
UserProfileFirstName = Column(String)
|
||||||
|
UserProfileLastName = Column(String)
|
||||||
|
InvoiceEmailAddress = Column(String)
|
||||||
|
ShippingCompany = Column(String)
|
||||||
|
ShippingFirstName = Column(String)
|
||||||
|
ShippingLastName = Column(String)
|
||||||
|
ShippingAddress1 = Column(String)
|
||||||
|
ShippingAddress2 = Column(String)
|
||||||
|
ShippingCity = Column(String)
|
||||||
|
ShippingState = Column(String)
|
||||||
|
ShippingPostalCode = Column(String)
|
||||||
|
|
||||||
|
|
||||||
|
class ItemDetail(Base):
|
||||||
|
__tablename__ = 'ItemDetail'
|
||||||
|
rowid = Column(Integer, primary_key=True, autoincrement=True)
|
||||||
|
OrderID = Column(String)
|
||||||
|
DocumentID = Column(String)
|
||||||
|
GLIJobNumber = Column(String)
|
||||||
|
ProductName = Column(String)
|
||||||
|
Quantity = Column(String)
|
||||||
|
ItemPrice = Column(REAL)
|
||||||
|
|
||||||
|
|
||||||
|
Session = sessionmaker(bind=engine)
|
||||||
|
session = Session()
|
||||||
|
|
||||||
|
|
||||||
|
def load_sheet(invoiceNumber):
|
||||||
|
|
||||||
|
# starting invoice sub-number
|
||||||
|
count = 2
|
||||||
|
|
||||||
|
#open the xlsx file from accounting and name the two sheets required
|
||||||
|
wb = load_workbook('1.xlsx', data_only=True)
|
||||||
|
shtInvoice = wb.get_sheet_by_name('Invoice')
|
||||||
|
shtItemDetail = wb.get_sheet_by_name('Item Detail')
|
||||||
|
|
||||||
|
#loop through each row in the Invoice sheet except for the first and last
|
||||||
|
#write each row to the database
|
||||||
|
for row in shtInvoice.iter_rows(min_row=2, max_row=shtInvoice.max_row-1):
|
||||||
|
session.add(Invoice(OrderID=row[0].value, InvoiceNumber=invoiceNumber + '-' + str(count), DateCreated=row[2].value,
|
||||||
|
ProductionCharges=row[4].value, ShippingCharges=row[5].value, AdjustmentsBalance=row[6].value,
|
||||||
|
DuePayment=row[7].value, ChargeCode=row[8].value, UserLogon=row[9].value, UserProfileFirstName=row[10].value,
|
||||||
|
UserProfileLastName=row[11].value, InvoiceEmailAddress=row[12].value, ShippingCompany=row[13].value,
|
||||||
|
ShippingFirstName=row[14].value, ShippingLastName=row[15].value, ShippingAddress1=row[16].value,
|
||||||
|
ShippingAddress2=row[17].value, ShippingCity=row[18].value, ShippingState=row[19].value,
|
||||||
|
ShippingPostalCode=row[20].value))
|
||||||
|
count = count + 1
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
for row in shtItemDetail.iter_rows(min_row=2, max_row=shtItemDetail.max_row-1):
|
||||||
|
session.add(ItemDetail(OrderID=row[0].value, DocumentID=row[1].value, GLIJobNumber=row[4].value, ProductName=row[5].value, Quantity=row[6].value, ItemPrice=row[7].value))
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def just_work():
|
||||||
|
orders = []
|
||||||
|
for order in session.query(Invoice).all():
|
||||||
|
orders.append(order.OrderID)
|
||||||
|
return orders
|
||||||
|
|
||||||
|
|
||||||
|
def record_lookup(record):
|
||||||
|
result = []
|
||||||
|
for lookup in session.query(Invoice).filter(Invoice.OrderID == record):
|
||||||
|
result.append(lookup.OrderID)
|
||||||
|
result.append(lookup.DateCreated)
|
||||||
|
result.append(lookup.UserLogon)
|
||||||
|
result.append(lookup.UserProfileFirstName)
|
||||||
|
result.append(lookup.UserProfileLastName)
|
||||||
|
result.append(lookup.ChargeCode)
|
||||||
|
result.append(lookup.InvoiceNumber)
|
||||||
|
result.append(lookup.InvoiceEmailAddress)
|
||||||
|
return result
|
||||||
32
TableSetup
Normal file
32
TableSetup
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
create table Invoice(
|
||||||
|
OrderID TEXT NOT NULL,
|
||||||
|
InvoiceNumber TEXT NOT NULL,
|
||||||
|
DateCreated TEXT NOT NULL,
|
||||||
|
ProductionCharges REAL NOT NULL,
|
||||||
|
ShippingCharges REAL NOT NULL,
|
||||||
|
AdjustmentsBalance REAL NOT NULL,
|
||||||
|
DuePayment REAL NOT NULL,
|
||||||
|
ChargeCode TEXT,
|
||||||
|
UserLogon TEXT NOT NULL,
|
||||||
|
UserProfileFirstName TEXT NOT NULL,
|
||||||
|
UserProfileLastName TEXT NOT NULL,
|
||||||
|
InvoiceEmailAddress TEXT NOT NULL,
|
||||||
|
ShippingCompany TEXT,
|
||||||
|
ShippingFirstName TEXT NOT NULL,
|
||||||
|
ShippingLastName TEXT NOT NULL,
|
||||||
|
ShippingAddress1 TEXT NOT NULL,
|
||||||
|
ShippingAddress2 TEXT,
|
||||||
|
ShippingCity TEXT NOT NULL,
|
||||||
|
ShippingState TEXT NOT NULL,
|
||||||
|
ShippingPostalCode TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
create table ItemDetail(
|
||||||
|
OrderID TEXT NOT NULL,
|
||||||
|
DocumentID TEXT NOT NULL,
|
||||||
|
GLIJobNumber TEXT NOT NULL,
|
||||||
|
ProductName TEXT NOT NULL,
|
||||||
|
Quantity INT NOT NULL,
|
||||||
|
ItemPrice REAL NOT NULL
|
||||||
|
);
|
||||||
20
main.py
Normal file
20
main.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import sendEmail
|
||||||
|
import InvoiceDatabase
|
||||||
|
|
||||||
|
running = True
|
||||||
|
|
||||||
|
while running is True:
|
||||||
|
print('1. load new excel file\n2. Send Test emails\n3. Send Invoices\n4. Quit')
|
||||||
|
option = int(input())
|
||||||
|
if option == 1:
|
||||||
|
print('Enter invoice number')
|
||||||
|
invoiceNumber = str(input())
|
||||||
|
InvoiceDatabase.load_sheet(invoiceNumber)
|
||||||
|
elif option == 2:
|
||||||
|
sendEmail.send_email(True,'ALL')
|
||||||
|
elif option == 3:
|
||||||
|
sendEmail.send_email()
|
||||||
|
elif option == 4:
|
||||||
|
running = False
|
||||||
|
else:
|
||||||
|
print('not an option')
|
||||||
7
requirements
Normal file
7
requirements
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
et-xmlfile==1.0.1
|
||||||
|
greenlet==1.0.0
|
||||||
|
importlib-metadata==3.7.3
|
||||||
|
openpyxl==3.0.7
|
||||||
|
SQLAlchemy==1.4.1
|
||||||
|
typing-extensions==3.7.4.3
|
||||||
|
zipp==3.4.1
|
||||||
125
sendEmail.py
Normal file
125
sendEmail.py
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
import smtplib
|
||||||
|
from email.mime.multipart import MIMEMultipart
|
||||||
|
from email.mime.text import MIMEText
|
||||||
|
from email.mime.base import MIMEBase
|
||||||
|
from datetime import datetime
|
||||||
|
import InvoiceDatabase
|
||||||
|
|
||||||
|
|
||||||
|
def send_email(test, record):
|
||||||
|
|
||||||
|
port = 25
|
||||||
|
smtp_server = "gll-com.mail.protection.outlook.com"
|
||||||
|
|
||||||
|
orders = InvoiceDatabase.just_work()
|
||||||
|
for each in orders:
|
||||||
|
info = InvoiceDatabase.record_lookup(each)
|
||||||
|
print(info)
|
||||||
|
OrderNumber = info[0]
|
||||||
|
OrderDate = info[1]
|
||||||
|
UserLogon = info[2]
|
||||||
|
Name = info[3] + ' ' + info[4]
|
||||||
|
ChargeCode = info[5]
|
||||||
|
InvoiceNumber = info[6]
|
||||||
|
InvoiceEmailAddress = info[7]
|
||||||
|
InvoiceDate = datetime.today().strftime('%m/%d/%Y')
|
||||||
|
|
||||||
|
|
||||||
|
body = '''
|
||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||||
|
<HTML><HEAD><TITLE>CFF Order Invoice</TITLE>
|
||||||
|
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
|
||||||
|
<META name=GENERATOR content="MSHTML 11.00.9600.18525">
|
||||||
|
<META name=Author content="">
|
||||||
|
<META name=Keywords content="">
|
||||||
|
<META name=Description content="">
|
||||||
|
<STYLE type=text/css>
|
||||||
|
p,
|
||||||
|
span,
|
||||||
|
a,
|
||||||
|
table,
|
||||||
|
td,
|
||||||
|
input,
|
||||||
|
textarea,
|
||||||
|
select,
|
||||||
|
option {{
|
||||||
|
font-family: Verdana, Tahoma, Geneva, Arial, Helvetica, sans-serif;
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 13px;
|
||||||
|
margin: 0;
|
||||||
|
}}
|
||||||
|
</STYLE>
|
||||||
|
</HEAD>
|
||||||
|
|
||||||
|
<BODY>
|
||||||
|
|
||||||
|
<TABLE style="BORDER-COLLAPSE: collapse" width="600">
|
||||||
|
|
||||||
|
<TR>
|
||||||
|
<TD style="BORDER-BOTTOM: #000000 1px solid" width="300"><IMG src="http://cff.gli.us.com/store/custom/images/GLIHeader.png"></TD>
|
||||||
|
<TD style="BORDER-BOTTOM: #000000 1px solid" width="300" align="right"><P style="FONT-SIZE: 18px; FONT-WEIGHT: normal; MARGIN-TOP: 10px"><I>INVOICE</I></P></TD>
|
||||||
|
</TR>
|
||||||
|
|
||||||
|
<TR vAlign="top">
|
||||||
|
<TD style="VERTICAL-ALIGN: top" vAlign="top" width="300">
|
||||||
|
<SPAN contentEditable=false style="" PFVar="AddressBlock">Address Block</SPAN></TD>
|
||||||
|
<TD style="VERTICAL-ALIGN: top" vAlign="top" width="300"> <BR><P><B>Make Checks Payable To:</B> <BR>Great Lakes Integrated <BR>4246 Hudson Dr.<BR>Stow, Ohio 44224<BR> </P></TD>
|
||||||
|
</TR>
|
||||||
|
|
||||||
|
<TR vAlign="top">
|
||||||
|
<TD style="VERTICAL-ALIGN: top" vAlign="top" width="300">
|
||||||
|
<P>
|
||||||
|
<B>Order Number:</B> {OrderNumber}
|
||||||
|
<BR><B>Order Date:</B> {OrderDate}
|
||||||
|
<BR><B>User Logon:</B> {UserLogon}
|
||||||
|
<BR><B>Name:</B> {Name}
|
||||||
|
<BR><B>Charge Code:</B> {ChargeCode}
|
||||||
|
</P>
|
||||||
|
</TD>
|
||||||
|
|
||||||
|
<TD style="VERTICAL-ALIGN: top" vAlign="top" width="300">
|
||||||
|
<P>
|
||||||
|
<B>Invoice Number:</B> {InvoiceNumber}
|
||||||
|
<BR><B>Invoice Date:</B> {InvoiceDate}
|
||||||
|
<BR><B>Customer Number:</B> 1925
|
||||||
|
<BR><B>Terms:</B>Due in 30 days
|
||||||
|
</P>
|
||||||
|
</TD>
|
||||||
|
</TR>
|
||||||
|
|
||||||
|
<TR>
|
||||||
|
<TD width="600" colSpan="2"><P style="MARGIN-TOP: 20px"><B>The order consists of the following items:</B> </P>
|
||||||
|
<SPAN contentEditable=false style="" PFVar="OrderDetail"></SPAN>
|
||||||
|
</TD>
|
||||||
|
</TR>
|
||||||
|
</TBODY>
|
||||||
|
</TABLE>
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
||||||
|
'''
|
||||||
|
HTMLpart = body.format(OrderNumber=OrderNumber, OrderDate=OrderDate, UserLogon=UserLogon, Name=Name,
|
||||||
|
ChargeCode=ChargeCode, InvoiceDate=InvoiceDate, InvoiceNumber=InvoiceNumber)
|
||||||
|
|
||||||
|
bodyHTML = MIMEText(HTMLpart, "html")
|
||||||
|
|
||||||
|
f = open("sample.html", 'w')
|
||||||
|
f.write(HTMLpart)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
msg = MIMEMultipart()
|
||||||
|
msg['Subject'] = 'INVOICE ' + InvoiceNumber
|
||||||
|
if test is True:
|
||||||
|
msg['To'] = 'ddembinski@gll.com'
|
||||||
|
else:
|
||||||
|
# msg['To'] = InvoiceEmailAddress
|
||||||
|
msg['To'] = 'ddembinski@gll.com'
|
||||||
|
msg['From'] = 'ddembinski@gll.com'
|
||||||
|
msg.add_header('Content-Type', 'text/html')
|
||||||
|
msg.attach(bodyHTML)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with smtplib.SMTP(smtp_server, port, timeout=120) as server:
|
||||||
|
server.sendmail(msg['From'], msg['To'], msg.as_string())
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
Reference in New Issue
Block a user