Beispiel #1
0
def refund_reason(request, contribution, wizard):
    addon = contribution.addon
    if not 'request' in wizard.get_progress():
        return redirect('support', contribution.pk, 'request')

    if contribution.transaction_id is None:
        messages.error(request,
            _('A refund cannot be applied for yet. Please try again later. '
              'If this error persists contact [email protected].'))
        paypal_log.info('Refund requested for contribution with no '
                        'transaction_id: %r' % contribution.pk)
        return redirect('account.purchases')

    if contribution.is_instant_refund():
        try:
            paypal.refund(contribution.paykey)
        except PaypalError, e:
            paypal_log.error('Paypal error with refund', exc_info=True)
            messages.error(request, _('There was an error with your instant '
                                      'refund.'))
            contribution.record_failed_refund(e)
            return redirect('account.purchases')

        refund = contribution.enqueue_refund(amo.REFUND_APPROVED_INSTANT)
        paypal_log.info('Refund %r issued for contribution %r' %
                        (refund.pk, contribution.pk))
        # Note: we have to wait for PayPal to issue an IPN before it's
        # completely refunded.
        messages.success(request, _('Refund is being processed.'))
        return redirect('account.purchases')
Beispiel #2
0
def refund_reason(request, contribution, wizard):
    if not contribution.can_we_refund():
        return http.HttpResponseForbidden()

    addon = contribution.addon
    if not 'request' in wizard.get_progress():
        return redirect('support', contribution.pk, 'request')

    if contribution.transaction_id is None:
        messages.error(request,
            _('A refund cannot be applied for yet. Please try again later. '
              'If this error persists contact [email protected].'))
        paypal_log.info('Refund requested for contribution with no '
                        'transaction_id: %r' % contribution.pk)
        return redirect('account.purchases')

    if contribution.is_instant_refund():
        try:
            paypal.refund(contribution.paykey)
        except PaypalError:
            paypal_log.error('Paypal error with refund', exc_info=True)
            messages.error(request, _('There was an error with your instant '
                                      'refund.'))
            return redirect('account.purchases')

        refund = contribution.enqueue_refund(amo.REFUND_APPROVED_INSTANT)
        paypal_log.info('Refund %r issued for contribution %r' %
                        (refund.pk, contribution.pk))
        # Note: we have to wait for PayPal to issue an IPN before it's
        # completely refunded.
        messages.success(request, _('Refund is being processed.'))
        return redirect('account.purchases')

    form = forms.ContactForm(request.POST or None)
    if request.method == 'POST' and form.is_valid():
        reason = form.cleaned_data['text']
        template = jingo.render_to_string(request,
            wizard.tpl('emails/refund-request.txt'),
            context={'product': addon,
                     'form': form,
                     'user': request.amo_user,
                     'contribution': contribution,
                     'refund_url': contribution.get_absolute_refund_url(),
                     'refund_reason': reason})
        log.info('Refund request sent by user: %s for addon: %s' %
                 (request.amo_user.pk, addon.pk))

        # L10n: %s is the app name.
        support_mail(_(u'New Refund Request for %s' % addon.name),
                     template, sender=settings.NOBODY_EMAIL,
                     recipients=[smart_str(addon.support_email)])

        # Add this refund request to the queue.
        contribution.enqueue_refund(amo.REFUND_PENDING, reason)
        return redirect(reverse('support',
                                args=[contribution.pk, 'refund-sent']))

    return wizard.render(request, wizard.tpl('refund.html'),
                         {'product': addon, 'contribution': contribution,
                          'form': form, 'title': _('Request Refund')})
Beispiel #3
0
def bango_portal_from_package(request, package_id):
    response = _redirect_to_bango_portal(package_id, "package_id: %s" % package_id)
    if "Location" in response:
        return HttpResponseRedirect(response["Location"])
    else:
        message = json.loads(response.content).get("__all__", response.content)[0]
        messages.error(request, message)
        return HttpResponseRedirect(reverse("lookup.home"))
Beispiel #4
0
def bango_portal_from_package(request, package_id):
    response = _redirect_to_bango_portal(int(package_id),
                                         'package_id: %s' % package_id)
    if 'Location' in response:
        return HttpResponseRedirect(response['Location'])
    else:
        message = (json.loads(response.content)
                       .get('__all__', response.content)[0])
        messages.error(request, message)
        return HttpResponseRedirect(reverse('lookup.home'))
Beispiel #5
0
def app_review(request, addon):
    version = addon.latest_version
    resp = None
    try:
        resp = _review(request, addon, version)
    except SigningError, exc:
        transaction.rollback()
        messages.error(request, "Signing Error: %s" % exc)
        transaction.commit()
        return redirect(reverse("reviewers.apps.review", args=[addon.app_slug]))
Beispiel #6
0
def bango_portal_from_package(request, package_id):
    response = _redirect_to_bango_portal(package_id,
                                         'package_id: %s' % package_id)
    if 'Location' in response:
        return HttpResponseRedirect(response['Location'])
    else:
        message = (json.loads(response.content).get('__all__',
                                                    response.content)[0])
        messages.error(request, message)
        return HttpResponseRedirect(reverse('lookup.home'))
Beispiel #7
0
def app_review(request, addon):
    version = addon.latest_version
    resp = None
    try:
        resp = _review(request, addon, version)
    except SigningError, exc:
        transaction.rollback()
        messages.error(request, 'Signing Error: %s' % exc)
        transaction.commit()
        return redirect(reverse('reviewers.apps.review',
                                args=[addon.app_slug]))
Beispiel #8
0
def user_delete(request, user_id):
    delete_form = DeleteUserForm(request.POST)
    if not delete_form.is_valid():
        messages.error(request, delete_form.errors)
        return HttpResponseRedirect(reverse('lookup.user_summary',
                                    args=[user_id]))

    user = get_object_or_404(UserProfile, pk=user_id)
    user.deleted = True
    user.save()  # Must call the save function to delete user.
    amo.log(amo.LOG.DELETE_USER_LOOKUP, user,
            details={'reason': delete_form.cleaned_data['delete_reason']},
            user=request.amo_user)

    return HttpResponseRedirect(reverse('lookup.user_summary', args=[user_id]))
Beispiel #9
0
def user_delete(request, user_id):
    delete_form = DeleteUserForm(request.POST)
    if not delete_form.is_valid():
        messages.error(request, delete_form.errors)
        return HttpResponseRedirect(reverse('lookup.user_summary',
                                    args=[user_id]))

    user = get_object_or_404(UserProfile, pk=user_id)
    user.deleted = True
    user.save()  # Must call the save function to delete user.
    amo.log(amo.LOG.DELETE_USER_LOOKUP, user,
            details={'reason': delete_form.cleaned_data['delete_reason']},
            user=request.amo_user)

    return HttpResponseRedirect(reverse('lookup.user_summary', args=[user_id]))
Beispiel #10
0
def transaction_refund(request, uuid):
    contrib = get_object_or_404(Contribution, uuid=uuid,
                                type=amo.CONTRIB_PURCHASE)
    if contrib.has_refund():
        messages.error(request, _('A refund has already been processed.'))
        return redirect(reverse('lookup.transaction_summary', args=[uuid]))

    form = TransactionRefundForm(request.POST)
    if not form.is_valid():
        messages.error(request, str(form.errors))
        return redirect(reverse('lookup.transaction_summary', args=[uuid]))

    try:
        res = client.api.bango.refund.post({'uuid': contrib.transaction_id})
    except (HttpClientError, HttpServerError):
        # Either doing something not supposed to or Solitude had an issue.
        log.exception('Refund error: %s' % uuid)
        messages.error(
            request,
            _('You cannot make a refund request for this transaction.'))
        return redirect(reverse('lookup.transaction_summary', args=[uuid]))

    if res['status'] == STATUS_PENDING:
        # Create pending Refund.
        contrib.enqueue_refund(
            status=amo.REFUND_PENDING,
            refund_reason=form.cleaned_data['refund_reason'],
            user=request.amo_user)
        log.info('Refund pending: %s' % uuid)
        email_buyer_refund_pending(contrib)
        messages.success(
            request, _('Refund for this transaction now pending.'))
    elif res['status'] == STATUS_COMPLETED:
        # Create approved Refund.
        contrib.enqueue_refund(
            status=amo.REFUND_APPROVED,
            refund_reason=form.cleaned_data['refund_reason'],
            user=request.amo_user)
        log.info('Refund approved: %s' % uuid)
        email_buyer_refund_approved(contrib)
        messages.success(
            request, _('Refund for this transaction successfully approved.'))
    elif res['status'] == STATUS_FAILED:
        # Bango no like.
        log.error('Refund failed: %s' % uuid)
        messages.error(
            request, _('Refund request for this transaction failed.'))

    return redirect(reverse('lookup.transaction_summary', args=[uuid]))
Beispiel #11
0
def refund_reason(request, contribution, wizard):
    addon = contribution.addon
    if not 'request' in wizard.get_progress():
        return redirect('support', contribution.pk, 'request')

    if contribution.transaction_id is None:
        messages.error(
            request,
            _('A refund cannot be applied for yet. Please try again later. '
              'If this error persists contact [email protected].'))
        paypal_log.info('Refund requested for contribution with no '
                        'transaction_id: %r' % contribution.pk)
        return redirect('account.purchases')

    if contribution.is_refunded():
        messages.error(request, _('This has already been refunded.'))
        paypal_log.info('Already refunded: %s' % contribution.pk)
        return redirect('account.purchases')

    if contribution.is_instant_refund():
        if waffle.flag_is_active(request, 'solitude-payments'):
            try:
                client.post_refund(data={'uuid': contribution.transaction_id})
            except client.Error, e:
                paypal_log.error('Paypal error with refund', exc_info=True)
                messages.error(
                    request,
                    _('There was an error with your '
                      'instant refund.'))
                contribution.record_failed_refund(e, request.amo_user)
                return redirect('account.purchases')
        else:
            # TODO(solitude): remove this.
            try:
                paypal.refund(contribution.paykey)
            except PaypalError, e:
                paypal_log.error('Paypal error with refund', exc_info=True)
                messages.error(
                    request,
                    _('There was an error with your '
                      'instant refund.'))
                contribution.record_failed_refund(e, request.amo_user)
                return redirect('account.purchases')
Beispiel #12
0
def refund_reason(request, contribution, wizard):
    addon = contribution.addon
    if not "request" in wizard.get_progress():
        return redirect("support", contribution.pk, "request")

    if contribution.transaction_id is None:
        messages.error(
            request,
            _(
                "A refund cannot be applied for yet. Please try again later. "
                "If this error persists contact [email protected]."
            ),
        )
        paypal_log.info("Refund requested for contribution with no " "transaction_id: %r" % contribution.pk)
        return redirect("account.purchases")

    if contribution.is_refunded():
        messages.error(request, _("This has already been refunded."))
        paypal_log.info("Already refunded: %s" % contribution.pk)
        return redirect("account.purchases")

    if contribution.is_instant_refund():
        if waffle.flag_is_active(request, "solitude-payments"):
            try:
                client.post_refund(data={"uuid": contribution.transaction_id})
            except client.Error, e:
                paypal_log.error("Paypal error with refund", exc_info=True)
                messages.error(request, _("There was an error with your " "instant refund."))
                contribution.record_failed_refund(e)
                return redirect("account.purchases")
        else:
            # TODO(solitude): remove this.
            try:
                paypal.refund(contribution.paykey)
            except PaypalError, e:
                paypal_log.error("Paypal error with refund", exc_info=True)
                messages.error(request, _("There was an error with your " "instant refund."))
                contribution.record_failed_refund(e)
                return redirect("account.purchases")
Beispiel #13
0
def refund_reason(request, contribution, wizard):
    addon = contribution.addon
    if not 'request' in wizard.get_progress():
        return redirect('support', contribution.pk, 'request')

    if contribution.transaction_id is None:
        messages.error(request,
            _('A refund cannot be applied for yet. Please try again later. '
              'If this error persists contact [email protected].'))
        paypal_log.info('Refund requested for contribution with no '
                        'transaction_id: %r' % contribution.pk)
        return redirect('account.purchases')

    if contribution.is_refunded():
        messages.error(request, _('This has already been refunded.'))
        paypal_log.info('Already refunded: %s' % contribution.pk)
        return redirect('account.purchases')

    if contribution.is_instant_refund():
        if waffle.flag_is_active(request, 'solitude-payments'):
            try:
                client.post_refund(data={'uuid': contribution.transaction_id})
            except client.Error, e:
                paypal_log.error('Paypal error with refund', exc_info=True)
                messages.error(request, _('There was an error with your '
                                          'instant refund.'))
                contribution.record_failed_refund(e, request.amo_user)
                return redirect('account.purchases')
        else:
            # TODO(solitude): remove this.
            try:
                paypal.refund(contribution.paykey)
            except PaypalError, e:
                paypal_log.error('Paypal error with refund', exc_info=True)
                messages.error(request, _('There was an error with your '
                                          'instant refund.'))
                contribution.record_failed_refund(e, request.amo_user)
                return redirect('account.purchases')
Beispiel #14
0
def refund_reason(request, contribution, wizard):
    addon = contribution.addon
    if not 'request' in wizard.get_progress():
        return redirect('support', contribution.pk, 'request')

    if contribution.transaction_id is None:
        messages.error(request,
            _('A refund cannot be applied for yet. Please try again later. '
              'If this error persists contact [email protected].'))
        paypal_log.info('Refund requested for contribution with no '
                        'transaction_id: %r' % contribution.pk)
        return redirect('account.purchases')

    if contribution.is_refunded():
        messages.error(request, _('This has already been refunded.'))
        paypal_log.info('Already refunded: %s' % contribution.pk)
        return redirect('account.purchases')

    if contribution.is_instant_refund():
        try:
            paypal.refund(contribution.paykey)
        except PaypalError, e:
            paypal_log.error('Paypal error with refund', exc_info=True)
            messages.error(request, _('There was an error with your instant '
                                      'refund.'))
            contribution.record_failed_refund(e)
            return redirect('account.purchases')

        refund = contribution.enqueue_refund(amo.REFUND_APPROVED_INSTANT)
        paypal_log.info('Refund %r issued for contribution %r' %
                        (refund.pk, contribution.pk))
        # Note: we have to wait for PayPal to issue an IPN before it's
        # completely refunded.
        messages.success(request, _('Refund is being processed.'))
        amo.log(amo.LOG.REFUND_INSTANT, addon)
        return redirect('account.purchases')
Beispiel #15
0
def refund_reason(request, contribution, wizard):
    if not contribution.can_we_refund():
        return http.HttpResponseForbidden()

    addon = contribution.addon
    if not "request" in wizard.get_progress():
        return redirect("support", contribution.pk, "request")

    if contribution.transaction_id is None:
        messages.error(
            request,
            _(
                "A refund cannot be applied for yet. Please try again later. "
                "If this error persists contact [email protected]."
            ),
        )
        paypal_log.info("Refund requested for contribution with no " "transaction_id: %r" % contribution.pk)
        return redirect("account.purchases")

    if contribution.is_instant_refund():
        paypal.refund(contribution.paykey)
        # TODO: Consider requiring a refund reason for instant refunds.
        refund = contribution.enqueue_refund(amo.REFUND_APPROVED_INSTANT)
        paypal_log.info("Refund %r issued for contribution %r" % (refund.pk, contribution.pk))
        # Note: we have to wait for PayPal to issue an IPN before it's
        # completely refunded.
        messages.success(request, _("Refund is being processed."))
        return redirect("account.purchases")

    form = forms.ContactForm(request.POST or None)
    if request.method == "POST" and form.is_valid():
        reason = form.cleaned_data["text"]
        template = jingo.render_to_string(
            request,
            wizard.tpl("emails/refund-request.txt"),
            context={
                "product": addon,
                "form": form,
                "user": request.amo_user,
                "contribution": contribution,
                "refund_url": contribution.get_absolute_refund_url(),
                "refund_reason": reason,
            },
        )
        log.info("Refund request sent by user: %s for addon: %s" % (request.amo_user.pk, addon.pk))

        # L10n: %s is the app name.
        support_mail(
            _(u"New Refund Request for %s" % addon.name),
            template,
            sender=settings.NOBODY_EMAIL,
            recipients=[smart_str(addon.support_email)],
        )

        # Add this refund request to the queue.
        contribution.enqueue_refund(amo.REFUND_PENDING, reason)
        return redirect(reverse("support", args=[contribution.pk, "refund-sent"]))

    return wizard.render(
        request,
        wizard.tpl("refund.html"),
        {"product": addon, "contribution": contribution, "form": form, "title": _("Request Refund")},
    )
Beispiel #16
0
def transaction_refund(request, tx_uuid):
    contrib = get_object_or_404(Contribution, uuid=tx_uuid, type=amo.CONTRIB_PURCHASE)
    refund_contribs = contrib.get_refund_contribs()
    refund_contrib = refund_contribs[0] if refund_contribs.exists() else None

    if refund_contrib:
        messages.error(request, _("A refund has already been processed."))
        return redirect(reverse("lookup.transaction_summary", args=[tx_uuid]))

    form = TransactionRefundForm(request.POST)
    if not form.is_valid():
        return jingo.render(
            request,
            "lookup/transaction_summary.html",
            dict(
                {"uuid": tx_uuid, "tx_refund_form": form, "tx_form": TransactionSearchForm()}.items()
                + _transaction_summary(tx_uuid).items()
            ),
        )

    data = {"uuid": contrib.transaction_id, "manual": form.cleaned_data["manual"]}
    if settings.BANGO_FAKE_REFUNDS:
        data["fake_response_status"] = {"responseCode": form.cleaned_data["fake"]}

    try:
        res = client.api.bango.refund.post(data)
    except (HttpClientError, HttpServerError):
        # Either doing something not supposed to or Solitude had an issue.
        log.exception("Refund error: %s" % tx_uuid)
        messages.error(request, _("You cannot make a refund request for this transaction."))
        return redirect(reverse("lookup.transaction_summary", args=[tx_uuid]))

    if res["status"] in [PENDING, COMPLETED]:
        # Create refund Contribution by cloning the payment Contribution.
        refund_contrib = Contribution.objects.get(id=contrib.id)
        refund_contrib.id = None
        refund_contrib.save()
        refund_contrib.update(
            type=amo.CONTRIB_REFUND,
            related=contrib,
            uuid=hashlib.md5(str(uuid.uuid4())).hexdigest(),
            amount=-refund_contrib.amount if refund_contrib.amount else None,
            transaction_id=res["uuid"],
        )

    if res["status"] == PENDING:
        # Create pending Refund.
        refund_contrib.enqueue_refund(
            amo.REFUND_PENDING, request.amo_user, refund_reason=form.cleaned_data["refund_reason"]
        )
        log.info("Refund pending: %s" % tx_uuid)
        email_buyer_refund_pending(contrib)
        messages.success(request, _("Refund for this transaction now pending."))
    elif res["status"] == COMPLETED:
        # Create approved Refund.
        refund_contrib.enqueue_refund(
            amo.REFUND_APPROVED, request.amo_user, refund_reason=form.cleaned_data["refund_reason"]
        )
        log.info("Refund approved: %s" % tx_uuid)
        email_buyer_refund_approved(contrib)
        messages.success(request, _("Refund for this transaction successfully approved."))
    elif res["status"] == FAILED:
        # Bango no like.
        log.error("Refund failed: %s" % tx_uuid)
        messages.error(request, _("Refund request for this transaction failed."))

    return redirect(reverse("lookup.transaction_summary", args=[tx_uuid]))
Beispiel #17
0
def transaction_refund(request, tx_uuid):
    contrib = get_object_or_404(Contribution,
                                uuid=tx_uuid,
                                type=amo.CONTRIB_PURCHASE)
    refund_contribs = contrib.get_refund_contribs()
    refund_contrib = refund_contribs[0] if refund_contribs.exists() else None

    if refund_contrib:
        messages.error(request, _('A refund has already been processed.'))
        return redirect(reverse('lookup.transaction_summary', args=[tx_uuid]))

    form = TransactionRefundForm(request.POST)
    if not form.is_valid():
        return jingo.render(
            request, 'lookup/transaction_summary.html',
            dict({
                'uuid': tx_uuid,
                'tx_refund_form': form,
                'tx_form': TransactionSearchForm()
            }.items() + _transaction_summary(tx_uuid).items()))

    try:
        res = client.api.bango.refund.post({'uuid': contrib.transaction_id})
    except (HttpClientError, HttpServerError):
        # Either doing something not supposed to or Solitude had an issue.
        log.exception('Refund error: %s' % tx_uuid)
        messages.error(
            request,
            _('You cannot make a refund request for this transaction.'))
        return redirect(reverse('lookup.transaction_summary', args=[tx_uuid]))

    if res['status'] in [PENDING, COMPLETED]:
        # Create refund Contribution by cloning the payment Contribution.
        refund_contrib = Contribution.objects.get(id=contrib.id)
        refund_contrib.id = None
        refund_contrib.save()
        refund_contrib.update(
            type=amo.CONTRIB_REFUND,
            related=contrib,
            uuid=hashlib.md5(str(uuid.uuid4())).hexdigest(),
            amount=-refund_contrib.amount if refund_contrib.amount else None,
            transaction_id=client.get(res['transaction'])['uuid'])

    if res['status'] == PENDING:
        # Create pending Refund.
        refund_contrib.enqueue_refund(
            amo.REFUND_PENDING,
            request.amo_user,
            refund_reason=form.cleaned_data['refund_reason'])
        log.info('Refund pending: %s' % tx_uuid)
        email_buyer_refund_pending(contrib)
        messages.success(request,
                         _('Refund for this transaction now pending.'))
    elif res['status'] == COMPLETED:
        # Create approved Refund.
        refund_contrib.enqueue_refund(
            amo.REFUND_APPROVED,
            request.amo_user,
            refund_reason=form.cleaned_data['refund_reason'])
        log.info('Refund approved: %s' % tx_uuid)
        email_buyer_refund_approved(contrib)
        messages.success(
            request, _('Refund for this transaction successfully approved.'))
    elif res['status'] == FAILED:
        # Bango no like.
        log.error('Refund failed: %s' % tx_uuid)
        messages.error(request,
                       _('Refund request for this transaction failed.'))

    return redirect(reverse('lookup.transaction_summary', args=[tx_uuid]))
Beispiel #18
0
def transaction_refund(request, tx_uuid):
    contrib = get_object_or_404(Contribution, uuid=tx_uuid,
                                type=amo.CONTRIB_PURCHASE)
    refund_contribs = contrib.get_refund_contribs()
    refund_contrib = refund_contribs[0] if refund_contribs.exists() else None

    if refund_contrib:
        messages.error(request, _('A refund has already been processed.'))
        return redirect(reverse('lookup.transaction_summary', args=[tx_uuid]))

    form = TransactionRefundForm(request.POST)
    if not form.is_valid():
        messages.error(request, str(form.errors))
        return redirect(reverse('lookup.transaction_summary', args=[tx_uuid]))

    try:
        res = client.api.bango.refund.post({'uuid': contrib.transaction_id})
    except (HttpClientError, HttpServerError):
        # Either doing something not supposed to or Solitude had an issue.
        log.exception('Refund error: %s' % tx_uuid)
        messages.error(
            request,
            _('You cannot make a refund request for this transaction.'))
        return redirect(reverse('lookup.transaction_summary', args=[tx_uuid]))

    if res['status'] in [PENDING, COMPLETED]:
        # Create refund Contribution by cloning the payment Contribution.
        refund_contrib = Contribution.objects.get(id=contrib.id)
        refund_contrib.id = None
        refund_contrib.save()
        refund_contrib.update(
            type=amo.CONTRIB_REFUND, related=contrib,
            uuid=hashlib.md5(str(uuid.uuid4())).hexdigest(),
            amount=-refund_contrib.amount if refund_contrib.amount else None,
            transaction_id=client.get(res['transaction'])['uuid'])

    if res['status'] == PENDING:
        # Create pending Refund.
        refund_contrib.enqueue_refund(
            amo.REFUND_PENDING, request.amo_user,
            refund_reason=form.cleaned_data['refund_reason'])
        log.info('Refund pending: %s' % tx_uuid)
        email_buyer_refund_pending(contrib)
        messages.success(
            request, _('Refund for this transaction now pending.'))
    elif res['status'] == COMPLETED:
        # Create approved Refund.
        refund_contrib.enqueue_refund(
            amo.REFUND_APPROVED, request.amo_user,
            refund_reason=form.cleaned_data['refund_reason'])
        log.info('Refund approved: %s' % tx_uuid)
        email_buyer_refund_approved(contrib)
        messages.success(
            request, _('Refund for this transaction successfully approved.'))
    elif res['status'] == FAILED:
        # Bango no like.
        log.error('Refund failed: %s' % tx_uuid)
        messages.error(
            request, _('Refund request for this transaction failed.'))

    return redirect(reverse('lookup.transaction_summary', args=[tx_uuid]))