X-Git-Url: http://git.ipfire.org/?p=ipfire.org.git;a=blobdiff_plain;f=src%2Fweb%2Fdonate.py;fp=src%2Fweb%2Fdonate.py;h=bae215745af82879887c0c510f22a932b4f9e427;hp=3d87e2a6472b99472bba16862052bdb6e494078e;hb=6412f1c5b81a4679aff3bc2c9c08f6a1c8aac025;hpb=28ce811c6fb944970186f6dffb9616cef3d61cc0 diff --git a/src/web/donate.py b/src/web/donate.py index 3d87e2a6..bae21574 100644 --- a/src/web/donate.py +++ b/src/web/donate.py @@ -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¤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") @@ -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):