commit a bunch of invoice related stuff - generate pdf invoice, save to archive, email to customer

This commit is contained in:
Thomas Steen Rasmussen 2016-05-30 16:58:55 +02:00
parent aba0596252
commit 935af5f188
7 changed files with 162 additions and 58 deletions

View file

@ -103,3 +103,5 @@ TICKET_CATEGORY_ID = env('TICKET_CATEGORY_ID')
COINIFY_API_KEY = env('COINIFY_API_KEY')
COINIFY_API_SECRET = env('COINIFY_API_SECRET')
PDF_ARCHIVE_PATH='/usr/local/www/pdf_arhcive/'

View file

@ -7,6 +7,7 @@ EMAIL_HOST_USER='mymailuser'
EMAIL_HOST_PASSWORD='mymailpassword'
EMAIL_USE_TLS=True
EMAIL_FROM='noreply@example.com'
ARCHIVE_EMAIL='archive@example.com'
EPAY_MERCHANT_NUMBER=something
EPAY_MD5_SECRET=something
TICKET_CATEGORY_ID=''

View file

@ -20,6 +20,7 @@ EMAIL_HOST_PASSWORD = env('EMAIL_HOST_PASSWORD')
EMAIL_USE_TLS = env('EMAIL_USE_TLS')
DEFAULT_FROM_EMAIL = env('DEFAULT_FROM_EMAIL')
SERVER_EMAIL = env('DEFAULT_FROM_EMAIL')
ARCHIVE_EMAIL = env('ARCHIVE_EMAIL')
LOGGING = {
'version': 1,

68
shop/email.py Normal file
View file

@ -0,0 +1,68 @@
from django.core.mail import EmailMultiAlternatives
from django.conf import settings
from django.template.loader import render_to_string
def send_email(emailtype, recipient, formatdict, subject, sender='BornHack <noreply@bornhack.dk>', attachment=None):
### determine email type, set template and attachment vars
html_template=None
if emailtype == 'invoice':
text_template = 'emails/invoice.txt'
html_template = 'emails/invoice.html'
attachment_filename = formatdict['attachmentname']
elif emailtype == 'testmail':
text_template = 'emails/testmail.txt'
else:
print 'Unknown email type: %s' % emailtype
return False
try:
### put the basic email together
msg = EmailMultiAlternatives(subject, render_to_string(text_template, formatdict), sender, [recipient], [settings.ARCHIVE_EMAIL])
### is there a html version of this email?
if html_template:
msg.attach_alternative(render_to_string(html_template, formatdict), 'text/html')
### is there an attachment to this mail?
if attachment:
msg.attach(attachment_filename, attachment, 'application/pdf')
except Exception as E:
print 'exception while rendering email: %s' % E
return False
### send the email
msg.send()
### all good
return True
def send_invoice_email(invoice, attachment):
# put formatdict together
formatdict = {
'order': invoice.order,
'attachmentname': invoice.filename,
}
subject = 'BornHack invoice %s' % order.pk
# send mail
return send_email(
emailtype='invoice',
recipient=order.user.email,
formatdict=formatdict,
subject=subject,
sender='noreply@bornfiber.dk',
)
def send_test_email(recipient):
return send_email(
emailtype='testmail',
recipient=recipient,
subject='testmail from bornhack website',
)

View file

@ -5,7 +5,7 @@ from shop.email import send_invoice_email
class Command(BaseCommand):
args = 'none'
help = 'Send out invoices that has not been sent yet'
help = 'Send out invoices that have not been sent yet'
def handle(self, *args, **options):
self.stdout.write('Invoice worker running...')
@ -14,25 +14,47 @@ class Command(BaseCommand):
for order in Order.objects.filter(paid=True, invoice__isnull=True):
### generate invoice for this Order
Invoice.objects.create(order=order)
self.stdout.write('Generated Invoice object for order %s' % order)
### check if we need to generate any pdf invoices
for invoice in Invoice.objects.filter(pdf_generated=False):
# put the dict with data for the pdf together
formatdict = {
'invoice': invoice,
}
# generate the pdf
try:
pdffile = generate_pdf_letter(
filename=invoice.filename,
template='invoice.html',
formatdict=formatdict,
)
self.stdout.write('Generated pdf for invoice %s' % invoice)
except Exception as E:
self.stdout.write('ERROR: Unable to generate PDF file for invoice #%s. Error: %s' % (invoice.pk, E))
continue
# so, do we have a pdf?
if not pdffile:
self.stdout.write('ERROR: Unable to generate PDF file for invoice #%s' % invoice.pk)
continue
# update invoice object
invoice.pdf_generated=True
invoice.save()
### check if we need to send out any invoices
for invoice in Invoice.objects.filter(sent_to_customer=False):
### generate PDF invoice
try:
pdffile = generate_pdf_letter('invoice.html', formatdict)
except Exception as E:
self.stdout.write('ERROR: Unable to generate PDF file. Error: %s' % E)
continue
if not pdffile:
self.stdout.write('ERROR: Unable to generate PDF file')
continue
for invoice in Invoice.objects.filter(sent_to_customer=False, pdf_generated=True):
# read the pdf invoice from the archive
with open(settings.INVOICE_ARCHIVE_PATH+invoice.filename, 'r') as fh:
pdffile = fh.read()
if send_invoice_email(recipient=invoice.order.user.email, invoice=invoice, attachment=pdffile):
# send the email
if send_invoice_email(invoice=invoice, attachment=pdffile):
self.stdout.write('OK: Invoice email sent to %s' % order.user.email)
invoice.sent_to_customer=True
invoice.save()
else:
self.stdout.write('ERROR: Unable to send invoice email to %s' % order.user.email)
self.stdout.write('ERROR: Unable to send invoice email for order %s to %s' % (order.pk, order.user.email))
### pause for a bit
sleep(60)

View file

@ -252,6 +252,7 @@ class EpayPayment(CreatedUpdatedModel, UUIDModel):
class Invoice(CreatedUpdatedModel):
order = models.OneToOneField('shop.Order')
pdf_generated = models.BooleanField(default=False)
sent_to_customer = models.BooleanField(default=False)
def __str__(self):
@ -263,6 +264,10 @@ class Invoice(CreatedUpdatedModel):
self.sent_to_customer,
)
@property
def filename(self):
return 'bornhack_invoice_%s.pdf' % self.pk
class CoinifyAPIInvoice(CreatedUpdatedModel):
invoicejson = JSONField()

View file

@ -1,45 +1,50 @@
from wkhtmltopdf.views import PDFTemplateResponse
from PyPDF2 import PdfFileWriter, PdfFileReader
from django.test.client import RequestFactory
from django.conf import settings
import StringIO
def generate_pdf_letter(template, formatdict):
### produce text-only PDF from template
pdfgenerator = PDFTemplateResponse(
request=RequestFactory().get('/'),
template=template,
context=formatdict,
cmd_options={
'margin-top': 40,
'margin-bottom': 50,
},
)
textonlypdf = StringIO.StringIO()
textonlypdf.write(pdfgenerator.rendered_content)
### create a blank pdf to work with
finalpdf = PdfFileWriter()
### open the text-only pdf
pdfreader = PdfFileReader(textonlypdf)
### get watermark from watermark file
watermark = PdfFileReader(open(settings.LETTERHEAD_PDF_PATH, 'rb'))
### add the watermark to all pages
for pagenum in xrange(pdfreader.getNumPages()):
page = pdfreader.getPage(pagenum)
try:
page.mergePage(watermark.getPage(0))
except ValueError:
### watermark pdf might be broken?
return False
### add page to output
finalpdf.addPage(page)
### return a file object with the data
returnfile = StringIO.StringIO()
finalpdf.write(returnfile)
return returnfile
from wkhtmltopdf.views import PDFTemplateResponse
from PyPDF2 import PdfFileWriter, PdfFileReader
from django.test.client import RequestFactory
from django.conf import settings
import StringIO
def generate_pdf_letter(filename, template, formatdict):
### produce text-only PDF from template
pdfgenerator = PDFTemplateResponse(
request=RequestFactory().get('/'),
template=template,
context=formatdict,
cmd_options={
'margin-top': 40,
'margin-bottom': 50,
},
)
textonlypdf = StringIO.StringIO()
textonlypdf.write(pdfgenerator.rendered_content)
### create a blank pdf to work with
finalpdf = PdfFileWriter()
### open the text-only pdf
pdfreader = PdfFileReader(textonlypdf)
### get watermark from watermark file
watermark = PdfFileReader(open(settings.LETTERHEAD_PDF_PATH, 'rb'))
### add the watermark to all pages
for pagenum in xrange(pdfreader.getNumPages()):
page = pdfreader.getPage(pagenum)
try:
page.mergePage(watermark.getPage(0))
except ValueError:
### watermark pdf might be broken?
return False
### add page to output
finalpdf.addPage(page)
### save the generated pdf to the archive
with open(settings.PDF_ARCHIVE_PATH+filename, 'w') as fh:
finalpdf.write(fh)
self.stdout.write('Saved pdf to archive: %s' % settings.PDF_ARCHIVE_PATH+filename)
### return a file object with the data
returnfile = StringIO.StringIO()
finalpdf.write(returnfile)
return returnfile