Example #1
0
    def get_affected_records(self):
        """
        Retrieve the donations and payouts that will be affected by taking a cut.
        """
        affected = {}

        donations = self.object.local_payment.order_payment.order.donations.select_related(
            'project'
        )

        for donation in donations:
            payouts = donation.project.projectpayout_set.all()
            in_progress_payout, updateable_payout, new_payout, new_status = None, None, None, False  # defaults

            if not payouts.exists():
                new_status = donation.order.get_status_mapping(self.object.payment_type)
            else:
                updateable_payout = payouts.filter(status=StatusDefinition.NEW, protected=False).first()
                if updateable_payout is not None:
                    new_status = donation.order.get_status_mapping(self.object.payment_type)
                else:
                    # figure out if we can take cut from an unprocessed payout
                    in_progress_payout = payouts.filter(status=StatusDefinition.IN_PROGRESS).first()
                    if in_progress_payout is None:
                        new_payout = ProjectPayout(
                            project=donation.project,
                            protected=True,
                            amount_raised=0,
                            amount_payable=0,
                            organization_fee=-donation.amount,
                            planned=ProjectPayout.get_next_planned_date(),
                            description_line1='Taking cut from organization fees',
                            description_line2='from failed payment %d' % self.object.local_payment.pk,
                        )
                        new_payout.save()

            affected[donation] = {
                'new_status': new_status,
                'updateable_payout': updateable_payout,
                'in_progress_payout': in_progress_payout,
                'new_payout': new_payout
            }

        return affected
Example #2
0
 def export_sepa(self, request, queryset):
     """
     Dowload a sepa file with selected ProjectPayments
     """
     objs = queryset.all()
     if not request.user.is_staff:
         raise PermissionDenied
     response = HttpResponse()
     date = timezone.datetime.strftime(timezone.now(), '%Y%m%d%H%I%S')
     response['Content-Disposition'] = 'attachment; ' \
                                       'filename=payments_sepa%s.xml' % date
     response.write(ProjectPayout.create_sepa_xml(objs))
     return response
Example #3
0
def create_payout_finished_project(sender, instance, created, **kwargs):
    """
    Create or update Payout for finished projects.
    Project finish when deadline is hit or when it's changed manually in admin.
    """
    from bluebottle.payouts.models import ProjectPayout
    from localflavor.generic.validators import IBANValidator

    project = instance

    if project.status.slug in ['done-complete', 'done-incomplete'] \
            and project.amount_asked:

        next_date = ProjectPayout.get_next_planned_date()

        payouts = ProjectPayout.objects.filter(project=project)
        if payouts.count():
            # Get the latest payout
            payout = payouts.order_by('-created').all()[0]

            if payout.status == StatusDefinition.NEW:
                # Update planned payout date for new Payouts
                payout.calculate_amounts()
                payout.planned = next_date
                payout.save()
        else:

            if project.campaign_started:
                # Create new Payout
                payout = ProjectPayout(
                    planned=next_date,
                    project=project
                )

                # Calculate amounts
                payout.calculate_amounts()

                if project.is_closed:
                    payout.status = StatusDefinition.SETTLED

                # Set payment details
                try:
                    IBANValidator()(project.account_number)
                    payout.receiver_account_iban = project.account_number
                except ValidationError as e:
                    logger.info(
                        "IBAN error payout {0}, project: {1}: {2}".format(
                            payout.id, project.id, e.message))

                payout.receiver_account_bic = project.account_bic
                payout.receiver_account_number = project.account_number
                payout.receiver_account_name = project.account_holder_name
                payout.receiver_account_city = project.account_holder_city
                payout.receiver_account_country = project.account_bank_country.name

                payout.save()
Example #4
0
    def form_valid(self, form):
        with db_transaction.atomic():
            order = Order.objects.create(
                user=self.request.user,
                order_type='manual',
                total=form.cleaned_data['amount']
            )

            form.instance.order = order
            form.instance.anonymous = True
            self.object = donation = form.save()

            order_payment = OrderPayment.objects.create(
                user=self.request.user,
                order=order,
                amount=donation.amount,
                payment_method='manual'
            )
            payment = ManualPayment.objects.create(
                amount=donation.amount,
                bank_transaction=self.transaction,
                user=self.request.user,
                order_payment=order_payment
            )

            # pull us through the statuses to consider it done
            payment.status = StatusDefinition.AUTHORIZED
            payment.save()
            payment.status = StatusDefinition.SETTLED
            payment.save()

            # update/create the required payout
            project = donation.project
            project.update_amounts()
            payouts = ProjectPayout.objects.filter(project=project)

            # check the payouts and only update 'new' payouts, else create a new payout
            if payouts.exists():
                updateable = payouts.filter(status=StatusDefinition.NEW).first()  # only new payouts can be updated
                if updateable is None:
                    rules = payouts.values_list('payout_rule', flat=True).distinct()
                    if len(rules) == 1:
                        rule = rules[0]
                        _message = messages.success
                        msg = _('Created a new project payout with payment rule {rule}')
                    else:
                        _message = messages.warning
                        msg = _('There were {n} payout rules, the choosen rule was: \'{rule}\'')

                    # create a new payout, since the other payouts are on their way for processing and can't be altered
                    payout = ProjectPayout(
                        planned=ProjectPayout.get_next_planned_date(),
                        project=project,
                        payout_rule=rule,
                        protected=True
                    )

                    # we need to manually calculate the amounts, else all project donations will be taken into account
                    # FIXME: this needs to be refactored on the BB_PAYOUT level!
                    calculator = payout.get_calculator()
                    payout.calculate_payable_and_fee(calculator, donation.amount)
                    payout.save()
                    rule = dict(ProjectPayout.PayoutRules.choices)[rule]
                    _message(self.request, msg.format(n=len(rules), rule=rule))
                else:
                    # there is a payout that is still 'new', update that one
                    if updateable.protected is False:
                        updateable.calculate_amounts()
                    else:
                        # this is already an 'irregular' payout, so add the diff
                        # manually. There should be a journal entry for the modification
                        updateable.amount_raised += donation.amount
                        calculator = updateable.get_calculator()
                        updateable.calculate_payable_and_fee(calculator, updateable.get_amount_raised())
                        updateable.save()

                    messages.success(
                        self.request,
                        _('Created a manual donation and updated project payout %r') % updateable
                    )

                # NOTE theoretically there is a situation where the only updateable
                # payout is a payout for an open project and the payout is protected
                # It would then theoretically be possible to make a new donation via
                # the web interface and the project payout will not be re-calculateable

            self.transaction.status = BankTransaction.IntegrityStatus.Valid
            self.transaction.save()

            # TODO FIXME: organization payouts?! recalculate?

        return redirect(self.get_success_url())
Example #5
0
def create_payout_finished_project(sender, instance, created, **kwargs):
    """
    Create or update Payout for finished projects.
    Project finish when deadline is hit or when it's changed manually in admin.
    """
    from bluebottle.payouts.models import ProjectPayout
    from localflavor.generic.validators import IBANValidator

    project = instance

    if project.status.slug in ['done-complete', 'done-incomplete'] \
            and project.amount_asked:

        next_date = ProjectPayout.get_next_planned_date()

        payouts = ProjectPayout.objects.filter(project=project)
        if payouts.count():
            # Get the latest payout
            payout = payouts.order_by('-created').all()[0]

            if payout.status == StatusDefinition.NEW:
                # Update planned payout date for new Payouts
                payout.calculate_amounts()
                payout.planned = next_date
                payout.save()
        else:

            if project.campaign_started:
                # Create new Payout
                payout = ProjectPayout(planned=next_date, project=project)

                # Calculate amounts
                payout.calculate_amounts()

                if project.is_closed:
                    payout.status = StatusDefinition.SETTLED

                # Set payment details
                try:
                    IBANValidator()(project.account_number)
                    payout.receiver_account_iban = project.account_number
                except ValidationError as e:
                    logger.info(
                        "IBAN error payout {0}, project: {1}: {2}".format(
                            payout.id, project.id, e.message))

                payout.receiver_account_details = project.account_details or ''
                payout.receiver_account_number = project.account_number or ''
                payout.receiver_account_name = project.account_holder_name or ''
                payout.receiver_account_city = project.account_holder_city or ''
                try:
                    payout.receiver_account_country = project.account_bank_country.name
                except AttributeError:
                    payout.receiver_account_country = ''
                payout.save()