from . import base
+SKUS = {
+ "monthly" : "IPFIRE-DONATION-MONTHLY",
+ "quarterly" : "IPFIRE-DONATION-QUARTERLY",
+ "yearly" : "IPFIRE-DONATION-YEARLY",
+}
+DEFAULT_SKU = "IPFIRE-DONATION"
+
class DonateHandler(base.BaseHandler):
def get(self):
if self.current_user:
@base.ratelimit(minutes=15, requests=5)
async def post(self):
+ type = self.get_argument("type")
+ if not type in ("individual", "organization"):
+ raise tornado.web.HTTPError(400, "type is of an invalid value: %s" % type)
+
amount = self.get_argument("amount")
currency = self.get_argument("currency", "EUR")
frequency = self.get_argument("frequency")
- # Collect donor information
- donor = {
+ organization = None
+ locale = self.get_browser_locale()
+
+ # Get organization information
+ if type == "organization":
+ organization = {
+ "name" : self.get_argument("organization"),
+ "vat_number" : self.get_argument("vat_number", None),
+ }
+
+ # Collect person information
+ person = {
"email" : self.get_argument("email"),
"title" : self.get_argument("title"),
"first_name" : self.get_argument("first_name"),
"last_name" : self.get_argument("last_name"),
+ "locale" : locale.code,
}
# Collect address information
# Send everything to Zeiterfassung
try:
- # Search for person or create a new one
- response = await self.backend.zeiterfassung.send_request(
- "/api/v1/persons/search", **donor
- )
+ # Create a new organization
+ if organization:
+ organization = await self._create_organization(organization, address)
- if not response:
- response = await self.backend.zeiterfassung.send_request(
- "/api/v1/persons/create", **donor, **address
- )
-
- person = response.get("number")
+ # Create a person
+ person = await self._create_person(person, address, organization)
- donation = {
- "person" : person,
+ # Create a new order
+ order = await self._create_order(person=person, currency=currency)
- # $$$
- "amount" : amount,
- "currency" : currency,
+ # Add donation to the order
+ await self._create_donation(order, frequency, amount, currency,
+ vat_included=(type == "individual"))
- # Is this a recurring donation?
- "recurring" : frequency == "monthly",
+ # Submit the order
+ needs_payment = await self._submit_order(order)
- # Add URLs to redirect the user back
- "success_url" : "https://%s/donate/thank-you" % self.request.host,
- "error_url" : "https://%s/donate/error" % self.request.host,
- "back_url" : "https://%s/donate?amount=%s¤cy=%s&frequency=%s" %
- (self.request.host, amount, currency, frequency),
- }
-
- # Create donation
- response = await self.backend.zeiterfassung.send_request(
- "/api/v1/donations/create/ipfire-project", **donation, **address)
+ # Pay the order
+ if needs_payment:
+ redirect_url = await self._pay_order(order)
+ else:
+ redirect_url = "https://%s/donate/thank-you" % self.request.host
# Redirect the user to the payment page
- redirect_url = response.get("redirect_url")
if not redirect_url:
raise tornado.web.HTTPError(500, "Did not receive a redirect URL")
except Exception:
raise
+ async def _create_organization(self, organization, address):
+ # Check if we have an existing organization
+ response = await self.backend.zeiterfassung.send_request(
+ "/api/v1/organizations/search", **organization,
+ )
+
+ # Update details if we found a match
+ if response:
+ number = response.get("number")
+
+ # Update name
+ await self.backend.zeiterfassung.send_request(
+ "/api/v1/organizations/%s/name" % number, **organization
+ )
+
+ # Update VAT number
+ vat_number = organization.get("vat_number", None)
+ if vat_number:
+ await self.backend.zeiterfassung.send_request(
+ "/api/v1/organizations/%s/vat-number" % number, vat_number=vat_number,
+ )
+
+ # Update address
+ await self.backend.zeiterfassung.send_request(
+ "/api/v1/organizations/%s/address" % number, **address,
+ )
+
+ return number
+
+ # Otherwise we will create a new one
+ response = await self.backend.zeiterfassung.send_request(
+ "/api/v1/organizations/create", **organization, **address,
+ )
+
+ # Return the organization's number
+ return response.get("number")
+
+ async def _create_person(self, person, address, organization=None):
+ """
+ Searches for a matching person or creates a new one
+ """
+ # Check if we have an existing person
+ response = await self.backend.zeiterfassung.send_request(
+ "/api/v1/persons/search", **person
+ )
+
+ # Update details if we found a match
+ if response:
+ number = response.get("number")
+
+ # Update name
+ await self.backend.zeiterfassung.send_request(
+ "/api/v1/persons/%s/name" % number, **person,
+ )
+
+ # Update address
+ await self.backend.zeiterfassung.send_request(
+ "/api/v1/persons/%s/address" % number, **address,
+ )
+
+ return number
+
+ # If not, we will create a new one
+ response = await self.backend.zeiterfassung.send_request(
+ "/api/v1/persons/create", organization=organization, **person, **address
+ )
+
+ # Return the persons's number
+ return response.get("number")
+
+ async def _create_order(self, person, currency=None):
+ """
+ Creates a new order and returns its ID
+ """
+ response = await self.backend.zeiterfassung.send_request(
+ "/api/v1/orders/create", person=person, currency=currency,
+ )
+
+ # Return the order number
+ return response.get("number")
+
+ async def _create_donation(self, order, frequency, amount, currency,
+ vat_included=False):
+ """
+ Creates a new donation
+ """
+ # Select the correct product
+ try:
+ sku = SKUS[frequency]
+ except KeyError:
+ sku = DEFAULT_SKU
+
+ # Add it to the order
+ await self.backend.zeiterfassung.send_request(
+ "/api/v1/orders/%s/products/add" % order, sku=sku, quantity=1,
+ )
+
+ # Set the price
+ await self.backend.zeiterfassung.send_request(
+ "/api/v1/orders/%s/products/%s/price" % (order, sku),
+ price=amount, currency=currency, vat_included=vat_included,
+ )
+
+ async def _submit_order(self, order):
+ """
+ Submits the order
+ """
+ response = await self.backend.zeiterfassung.send_request(
+ "/api/v1/orders/%s/submit" % order,
+ )
+
+ # Return whether this needs payment
+ return not response.get("is_authorized")
+
+ async def _pay_order(self, order):
+ """
+ Pay the order
+ """
+ # Add URLs to redirect the user back
+ urls = {
+ "success_url" : "https://%s/donate/thank-you" % self.request.host,
+ "error_url" : "https://%s/donate/error" % self.request.host,
+ "back_url" : "https://%s/donate" % self.request.host,
+ }
+
+ # Send request
+ response = await self.backend.zeiterfassung.send_request(
+ "/api/v1/orders/%s/pay" % order, **urls,
+ )
+
+ # Return redirect URL
+ return response.get("redirect_url", None)
+
class ThankYouHandler(base.BaseHandler):
def get(self):