Example #1
0
 def initialize(self):
     self.name = "join"
     self.invoice_email = open('invoice-email.txt').read()
     self.welcome_email = open('welcome-email.txt').read()
     self.config = yaml.load(open('paypal.conf.yml'))[options.mode]
     self.paypal = PayPalAPI(self.config)
Example #2
0
class NewMemberFormHandler(tornado.web.RequestHandler):
    def initialize(self):
        self.name = "join"
        self.invoice_email = open('invoice-email.txt').read()
        self.welcome_email = open('welcome-email.txt').read()
        self.config = yaml.load(open('paypal.conf.yml'))[options.mode]
        self.paypal = PayPalAPI(self.config)

    def validate(self, data):
        try:
            form_data = json.loads(data)
        except:
            logging.error(data)
            raise HTTPError(400, "invalid form data")

        cleaned = {}
        mandatory_fields = [
            'given_names', 'surname', 'date_of_birth', 'residential_address',
            'residential_postcode', 'residential_state', 'residential_suburb',
            'submission', 'declaration', 'email', 'primary_phone',
            'membership_level', 'payment_method', 'payment_amount'
        ]

        optional_fields = [
            'gender', 'postal_address', 'postal_postcode', 'postal_state',
            'postal_suburb', 'secondary_phone', 'opt_out_state_parties',
            'other_party_in_last_12_months'
        ]

        for field in mandatory_fields:
            if field in form_data.keys():
                cleaned[field] = form_data[field]
            else:
                raise HTTPError(400, "missing fields: %s" % field)

        for field in optional_fields:
            if field in form_data.keys():
                cleaned[field] = form_data[field]

        if cleaned['membership_level'] not in ("full", "associate"):
            raise HTTPError(400, "invalid membership level")

        if cleaned['payment_method'] not in ("paypal", "direct_deposit", "cheque"):
            raise HTTPError(400, "invalid payment method")

        if cleaned['declaration'] != True or cleaned['submission'] != True:
            raise HTTPError(400, "invalid declaration or submission flag")

        try:
            x = abs(int(cleaned['payment_amount']) * 100)
            cleaned['payment_amount'] = x
            if x == 0:
                cleaned['payment_method'] = 'direct_deposit'
            #cleaned['payment_amount'] = 2000
        except:
            raise HTTPError(400, "invalid payment amount")

        try:
            cleaned['date_of_birth'] = datetime.datetime.strptime(cleaned['date_of_birth'], "%d/%m/%Y")
        except:
            logging.error(form_data)
            raise HTTPError(400, "invalid form data (date of birth)")

        return cleaned

    def create_member_record(self, data):
        id = uuid.uuid4()
        ts = datetime.datetime.utcnow()

        details = {
            "given_names": data['given_names'],
            "surname": data['surname'],
            "date_of_birth": data['date_of_birth'],
            "gender": data.get('gender', None),
            "residential_address": data['residential_address'],
            "residential_suburb": data['residential_suburb'],
            "residential_state": data['residential_state'],
            "residential_postcode": data['residential_postcode'],
            "postal_address": data.get('postal_address', None),
            "postal_suburb": data.get('postal_suburb', None),
            "postal_state": data.get('postal_state', None),
            "postal_postcode": data.get('postal_postcode', None),
            "email": data['email'],
            "primary_phone": data['primary_phone'],
            "secondary_phone": data.get('secondary_phone', None),
            "membership_level": data['membership_level'],
            "opt_out_state_parties": data.get('opt_out_state_parties', False),
            "other_party_in_last_12_months": data.get('other_party_in_last_12_months', None),
            "joined_on": ts
        }

        invoice = self.create_invoice_record(data['membership_level'],
                                             data['payment_method'],
                                             data['payment_amount'])

        return {
            "_id": id,
            "history": [{
                "action": "new",
                "ts": ts,
                "details": details,
                "v": 1
            },
            {
                "action": "new-invoice",
                "ts": invoice['ts'],
                "invoice": invoice,
                "v": 1
            }],
            "invoices": [invoice],
            "details": details,
            "v": 1
        }

    def create_invoice_record(self, membership_level, payment_method, price=None):
        if price is None:
            if membership_level in ("full", "associate"):
                price = 2000

        issued_date = datetime.datetime.utcnow()
        due_date = issued_date + datetime.timedelta(days=30)

        if membership_level == "full":
            out = {
                "v": 1,
                "ts": datetime.datetime.utcnow(),
                "items": [{
                    "item": "Full Membership - 12 Months",
                    "qty": 1,
                    "price": price
                }],
                "payment_method": payment_method,
                "due_date": due_date,
                "issued_date": issued_date,
                "status": "pending"
            }

            if payment_method != "paypal":
                c = self._get_counter('new_member')
                if c is None:
                    raise HTTPError(500, "mongodb keeled over at counter time")
                out["reference"] = "FM%s" % c

        elif membership_level == "associate":
            out = {
                "v": 1,
                "ts": datetime.datetime.utcnow(),
                "items": [{
                    "item": "Associate Membership - 12 Months",
                    "qty": 1,
                    "price": price
                }],
                "payment_method": payment_method,
                "due_date": due_date,
                "issued_date": issued_date,
                "status": "pending"
            }

            if payment_method != "paypal":
                c = self._get_counter('new_member_am')
                if c is None:
                    raise HTTPError(500, "mongodb keeled over at counter time")
                out["reference"] = "AM%s" % c
        return out

    def create_and_send_invoice(self, member, invoice):
        if invoice['payment_method'] == "paypal":
            biller_info = self.paypal.create_biller_info(
                member['given_names'],
                member['surname'],
                member['primary_phone'],
                member['residential_address'],
                None,
                member['residential_suburb'],
                member['residential_state'],
                member['residential_postcode']
            )

            response = self.paypal.create_and_send_invoice(
                self.config['email'],
                member['email'],
                self.paypal.get_merchant_info(),
                biller_info,
                self.paypal.create_invoice_item(invoice['items'][0]['item'], str(invoice['items'][0]['price']/100)),
                payment_terms="Net30"
            )

            if response['responseEnvelope']['ack'].startswith("Success"):
                invoice['reference'] = response['invoiceNumber']
                invoice['paypal_id'] = response['invoiceID']
                return invoice
            else:
                return None

        elif invoice['payment_method'] in ("direct_deposit", "cheque"):
            personal = {
              "name": "Pirate Party Australia Incorporated",
              "address": [],
              "contact": {
                "Email": "*****@*****.**",
                "Website": "<a href='http://pirateparty.org.au'>http://pirateparty.org.au</a>"
              },
              "business_number": "99 462 965 754",
              "payment_methods": [
                {
                  "Direct Deposit": [
                    "Name: Pirate Party Australia Incorporated",
                    "BSB: 012084",
                    "Account number: 213142205",
                    "Bank: ANZ"
                  ]
                }, {
                  "Cheque": [
                    "Address:",
                    "Pirate Party Australia",
                    "PO Box 385",
                    "Figtree NSW 2525"
                  ]
                }
              ]
            }


            member_level = "INVALID"
            if member['membership_level'] == "full":
                member_level = "Full Membership"
            elif member['membership_level'] == "associate":
                member_level = "Associate Membership"

            invoice_tmpl = {
                "regarding": member_level,
                "name": "%s %s" % (member['given_names'], member['surname']),
                "reference": invoice['reference'],
                "items": [
                  {
                    "rate_price": invoice['items'][0]['price'],
                    "tax": "0",
                    "description": invoice['items'][0]['item'],
                    "hours_qty": "1"
                  }
                ],
                "already_paid": "0",
                "details": "",
                "address": [
                  member['residential_address'],
                  "%s %s %s" % (member['residential_suburb'],
                      member['residential_state'], member['residential_postcode'])
                ],
                "date": invoice['issued_date'].strftime("%d/%m/%Y"),
                "message": "Thanks for joining Pirate Party Australia!",
                "payment_due": invoice['due_date'].strftime("%d/%m/%Y")
            }

            pdf_data = Invoice(invoice_tmpl, personal).to_pdf()
            try:
                sendmail(create_email(
                    frm="*****@*****.**",
                    to="%s %s <%s>" % (member['given_names'], member['surname'], member['email']),
                    subject="Pirate Party Membership Invoice (%s)" % invoice_tmpl['reference'],
                    text=self.invoice_email.format(name=member['given_names'].split(" ")[0]),
                    attachments=[create_attachment("ppau-invoice.pdf", pdf_data)]
                ))
                return invoice
            except Exception as e:
                logging.error("Failed to send invoice - %s" % e)
            return None
        else:
            raise Exception("How did you even get here?")

    def send_admin_message(self, member_record):
        member = member_record['details']
        msg = "New %s member: %s %s [%s] (%s)" % (member['membership_level'], member['given_names'],
                member['surname'], member['email'], member['residential_state'])
        id = member_record['_id'].hex

        sendmail(create_email(
                frm='*****@*****.**',
                reply_to=member['email'],
                to='*****@*****.**',
                subject=msg,
                text="%s\n%s\n$%s" % (id, member_record['invoices'][0]['payment_method'],
                    member_record['invoices'][0]['items'][0]['price']/100)
        ))
        logging.info("New member: %s %s" % (msg, id))
        logging.debug(dumps(member_record, indent=2))

    def send_confirmation(self, member_record):
        member = member_record['details']
        sendmail(create_email(
            frm="*****@*****.**",
            to="%s %s <%s>" % (member['given_names'], member['surname'], member['email']),
            subject="Welcome to Pirate Party Australia!",
            text=self.welcome_email.format(name=member['given_names'].split(" ")[0])
        ))

    def get(self):
        self.render(self.name + '.html', record=None)

    def post(self):
        data = self.validate(self.get_argument('data', None))
        member_record = self.create_member_record(data)
        invoice_record = self.create_and_send_invoice(member_record['details'], member_record['invoices'][0])
        if not invoice_record:
            raise HTTPError(500, "invoice failed to send")

        member_record['invoices'][0] = invoice_record
        if not safe_insert(db.members, member_record):
            raise HTTPError(500, "mongodb keeled over")

        self.send_confirmation(member_record)
        self.send_admin_message(member_record)

    def _get_counter(self, name):
        record = safe_modify(db.counters, {"_id": name}, {"$inc": {"count": 1}}, True)
        logging.info("Current count for '%s': %s" % (name, record['count']))
        if record != False:
            return record['count']