]> git.ipfire.org Git - ipfire.org.git/blobdiff - src/web/donate.py
Merge branch 'master' into new-design
[ipfire.org.git] / src / web / donate.py
index 3d87e2a6472b99472bba16862052bdb6e494078e..bae215745af82879887c0c510f22a932b4f9e427 100644 (file)
@@ -5,6 +5,13 @@ import tornado.web
 
 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:
@@ -34,16 +41,31 @@ class DonateHandler(base.BaseHandler):
 
        @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
@@ -58,41 +80,30 @@ class DonateHandler(base.BaseHandler):
 
                # 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&currency=%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")
 
@@ -102,6 +113,139 @@ class DonateHandler(base.BaseHandler):
                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):