diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d07d743..e5ffb50 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,12 +14,12 @@ jobs: - name: Build jazkarta.shop docker image run: docker build . -t jazkarta.shop env: - DOCKER_BUILDKIT: "1" + DOCKER_BUILDKIT: "1" - name: Start Plone server - run: docker-compose up -d + run: docker compose up -d env: - DOCKER_BUILDKIT: "1" + DOCKER_BUILDKIT: "1" - name: Check that jazkarta.shop was installed run: curl --fail -v http://localhost:8080/Plone/review-cart @@ -39,4 +39,4 @@ jobs: - name: Print plone server logs if: always() # This step should be also run when a previous step failed - run: docker-compose logs plone + run: docker compose logs plone diff --git a/docker-compose.yml b/docker-compose.yml index e5419ab..26fc222 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,7 +23,7 @@ services: - data:/data ports: - "8100" - # The `dummy` service is here to make sure `docker-compose up` exits only when + # The `dummy` service is here to make sure `docker compose up` exits only when # `plone`'s health is `healthy`. dummy: image: busybox diff --git a/jazkarta/shop/browser/checkout/authorize_net_accept_js.py b/jazkarta/shop/browser/checkout/authorize_net_accept_js.py index 9369543..1220a98 100644 --- a/jazkarta/shop/browser/checkout/authorize_net_accept_js.py +++ b/jazkarta/shop/browser/checkout/authorize_net_accept_js.py @@ -1,4 +1,5 @@ import six +import time from AccessControl import getSecurityManager from persistent.mapping import PersistentMapping from ZODB.POSException import ConflictError @@ -17,11 +18,16 @@ from ...utils import resolve_uid from ...utils import run_in_transaction from ...validators import is_email -import time +from ... import logger + +SUBSCRIPTION_SLEEP_INCREMENT = 2 +SUBSCRIPTION_RETRIES = 4 class CheckoutFormAuthorizeNetAcceptJs(CheckoutFormBase): - """ Renders a checkout form set up to submit through Stripe """ + """ Renders a checkout form set up to submit through authorize.net Accept.js + """ + index = ViewPageTemplateFile( '../templates/checkout_form_authorize_net_accept_js.pt') @@ -50,6 +56,31 @@ def refId(self): capture_payment = True is_recurring = False recurring_months = None + retries = 0 + + def retry_subscription_request(self, opaque_data, contact_info): + while self.retries < SUBSCRIPTION_RETRIES: + try: + return ARBCreateSubscriptionRequest( + self.cart, self.refId, opaque_data, contact_info, + months=self.recurring_months + ) + except PaymentProcessingException as e: + self.retries += 1 + # Raise the error once retries have been exceeded + if self.retries >= SUBSCRIPTION_RETRIES: + raise e + # Retry after delay for specific error + if 'Invalid OTS Token' in str(e): + delay = SUBSCRIPTION_SLEEP_INCREMENT * self.retries + logger.warn( + "Error on Auth.net subscription request. Retrying " + "({}) after {} seconds".format(self.retries, delay) + ) + time.sleep(delay) + continue + # Raise the error for any other error + raise e def handle_submit(self): if not len(self.cart.items): @@ -104,9 +135,9 @@ def handle_submit(self): try: if self.is_recurring: - response = ARBCreateSubscriptionRequest( - self.cart, self.refId, opaque_data, contact_info, - months=self.recurring_months) + response = self.retry_subscription_request( + opaque_data, contact_info + ) else: transactionType = ( 'authCaptureTransaction' if self.capture_payment @@ -116,7 +147,7 @@ def handle_submit(self): self.cart, self.refId, opaque_data, contact_info, transactionType=transactionType) except PaymentProcessingException as e: - self.error = e.message + self.error = str(e) if not self.error: try: diff --git a/jazkarta/shop/browser/checkout/stripe.py b/jazkarta/shop/browser/checkout/stripe.py index 6a34a0f..68b337f 100644 --- a/jazkarta/shop/browser/checkout/stripe.py +++ b/jazkarta/shop/browser/checkout/stripe.py @@ -78,10 +78,10 @@ def handle_submit(self): except PaymentProcessingException as e: charge_result = { 'success': False, - 'err_msg': e.message, + 'err_msg': str(e), 'err_code': getattr(e, 'code', None), } - self.error = e.message + self.error = str(e) if not self.error: try: