import factory from bluebottle.utils.model_dispatcher import get_order_model from bluebottle.utils.utils import StatusDefinition from bluebottle.payments.models import OrderPaymentAction from .accounts import BlueBottleUserFactory ORDER_MODEL = get_order_model() class OrderFactory(factory.DjangoModelFactory): FACTORY_FOR = ORDER_MODEL user = factory.SubFactory(BlueBottleUserFactory) status = StatusDefinition.CREATED class OrderActionFactory(factory.DjangoModelFactory): FACTORY_FOR = OrderPaymentAction
def form_valid(self, form): with db_transaction.atomic(): order = get_order_model().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, 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 ProjectPayout = get_project_payout_model() 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())