コード例 #1
0
    def perform_update(self):
        payment_client = PaymentClient()
        payments = payment_client.get_incomplete_payments()
        for payment in payments:
            if not self.should_be_checked(payment):
                continue

            payment_ref = payment['uuid']
            govuk_id = payment['processor_id']

            try:
                govuk_payment = payment_client.get_govuk_payment(govuk_id)
                previous_govuk_status = GovUkPaymentStatus.get_from_govuk_payment(
                    govuk_payment)
                govuk_status = payment_client.complete_payment_if_necessary(
                    payment, govuk_payment)

                # not yet finished and can't do anything so skip
                if govuk_status and not govuk_status.finished():
                    continue

                if previous_govuk_status != govuk_status:
                    # refresh govuk payment to get up-to-date fields (e.g. error codes)
                    govuk_payment = payment_client.get_govuk_payment(govuk_id)

                # if here, status is either success, failed, cancelled, error
                # or None (in case of govuk payment not found)
                payment_client.update_completed_payment(payment, govuk_payment)
            except OAuth2Error:
                logger.exception(
                    'Scheduled job: Authentication error while processing %s' %
                    payment_ref)
            except RequestException as error:
                error_message = 'Scheduled job: Payment check failed for ref %s' % payment_ref
                if hasattr(error, 'response') and hasattr(
                        error.response, 'content'):
                    error_message += '\nReceived: %s' % error.response.content
                logger.exception(error_message)
            except GovUkPaymentStatusException:
                # expected much of the time
                pass
コード例 #2
0
    def get(self, request, *args, **kwargs):
        payment_ref = self.request.GET.get('payment_ref')
        if not payment_ref:
            return clear_session_view(request)
        kwargs['short_payment_ref'] = payment_ref[:8].upper()
        try:
            # check payment status
            payment_client = PaymentClient()
            payment = payment_client.get_payment(payment_ref)

            # only continue if:
            # - the MTP payment is in pending (it moves to the 'taken' state by the cronjob x mins after
            #   the gov.uk payment succeeds)
            #   OR
            # - the MTP payment is in the 'taken' state (by the cronjob x mins after the gov.uk payment succeeded)
            #   but only for a limited period of time
            if not payment or not is_active_payment(payment):
                return clear_session_view(request)

            kwargs.update({
                'prisoner_name': payment['recipient_name'],
                'prisoner_number': payment['prisoner_number'],
                'amount': decimal.Decimal(payment['amount']) / 100,
            })

            if payment['status'] == 'taken':
                self.status = GovUkPaymentStatus.success
            else:
                # check gov.uk payment status
                govuk_id = payment['processor_id']
                govuk_payment = payment_client.get_govuk_payment(govuk_id)

                self.status = payment_client.complete_payment_if_necessary(
                    payment, govuk_payment)

                # here status can be either created, started, submitted, capturable, success, failed, cancelled, error
                # or None

                error_code = govuk_payment and govuk_payment.get(
                    'state', {}).get('code')

                # payment was cancelled programmatically (this would not currently happen)
                if self.status == GovUkPaymentStatus.cancelled:
                    # error_code is expected to be P0040
                    error_code == 'P0040' or logger.error(
                        f'Unexpected code for cancelled GOV.UK Pay payment {payment_ref}: {error_code}'
                    )
                    return render(request,
                                  'send_money/debit-card-cancelled.html')

                # the user cancelled the payment
                if self.status == GovUkPaymentStatus.failed and error_code == 'P0030':
                    return render(request,
                                  'send_money/debit-card-cancelled.html')

                # GOV.UK Pay session expired
                if self.status == GovUkPaymentStatus.failed and error_code == 'P0020':
                    return render(
                        request, 'send_money/debit-card-session-expired.html')

                # payment method was rejected by card issuer or processor
                # e.g. due to insufficient funds or risk management
                if self.status == GovUkPaymentStatus.failed:
                    # error_code is expected to be P0010
                    error_code == 'P0010' or logger.error(
                        f'Unexpected code for failed GOV.UK Pay payment {payment_ref}: {error_code}'
                    )
                    return render(request,
                                  'send_money/debit-card-declined.html')

                # here status can be either created, started, submitted, capturable, success, error
                # or None

                # treat statuses created, started, submitted or None as error as they should have never got here
                if not self.status or self.status.is_awaiting_user_input():
                    self.status = GovUkPaymentStatus.error

                # here status can be either capturable, success, error

        except OAuth2Error:
            logger.exception(
                'Authentication error while processing %(payment_ref)s',
                {'payment_ref': payment_ref},
            )
            self.status = GovUkPaymentStatus.error
        except RequestException as error:
            response_content = get_requests_exception_for_logging(error)
            logger.exception(
                'Payment check failed for ref %(payment_ref)s. Received: %(response_content)s',
                {
                    'payment_ref': payment_ref,
                    'response_content': response_content
                },
            )
            self.status = GovUkPaymentStatus.error
        except GovUkPaymentStatusException:
            logger.exception(
                'GOV.UK Pay returned unexpected status for ref %(payment_ref)s',
                {'payment_ref': payment_ref},
            )
            self.status = GovUkPaymentStatus.error

        response = super().get(request, *args, **kwargs)
        request.session.flush()
        return response