Skip to content

Commit

Permalink
WIP - create util function and call it within the transaction + response
Browse files Browse the repository at this point in the history
  • Loading branch information
nicktytarenko committed Jan 28, 2025
1 parent b7366e4 commit 08f2c3a
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 38 deletions.
67 changes: 67 additions & 0 deletions src/purchase/utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import decimal
import time

from rest_framework.response import Response

from purchase.related_models.constants.currency import USD
from reputation.distributions import create_purchase_distribution
from reputation.distributor import Distributor
from reputation.models import Escrow
from researchhub_document.related_models.constants.document_type import PREREGISTRATION
from utils.sentry import log_error


def distribute_support_to_authors(paper, purchase, amount):
Expand Down Expand Up @@ -31,3 +37,64 @@ def store_leftover_paper_support(paper, purchase, leftover_amount):
item=paper,
hold_type=Escrow.AUTHOR_RSC,
)


def create_fundraise_with_escrow(
user, unified_document, goal_amount, goal_currency=USD
):
"""
Helper function to create a fundraise with its associated escrow.
Returns (fundraise, error_response) tuple where error_response is None if successful
Note: This function should be called within a transaction.atomic() block
"""
from django.contrib.contenttypes.models import ContentType

from purchase.models import Fundraise
from reputation.models import Escrow

# Validate inputs
if not unified_document.document_type == PREREGISTRATION:
return None, Response(
{"message": "Fundraise must be for a preregistration"}, status=400
)

try:
goal_amount = decimal.Decimal(goal_amount)
if goal_amount <= 0:
return None, Response(

Check warning on line 65 in src/purchase/utils.py

View check run for this annotation

Codecov / codecov/patch

src/purchase/utils.py#L65

Added line #L65 was not covered by tests
{"message": "goal_amount must be greater than 0"}, status=400
)
except Exception as e:
log_error(e)
return None, Response({"detail": "Invalid goal_amount"}, status=400)

Check warning on line 70 in src/purchase/utils.py

View check run for this annotation

Codecov / codecov/patch

src/purchase/utils.py#L68-L70

Added lines #L68 - L70 were not covered by tests

if goal_currency != USD:
return None, Response({"message": "goal_currency must be USD"}, status=400)

Check warning on line 73 in src/purchase/utils.py

View check run for this annotation

Codecov / codecov/patch

src/purchase/utils.py#L73

Added line #L73 was not covered by tests

# Check if fundraise already exists
existing_fundraise = Fundraise.objects.filter(
unified_document=unified_document
).first()
if existing_fundraise:
return None, Response({"message": "Fundraise already exists"}, status=400)

# Create fundraise object
fundraise = Fundraise.objects.create(
created_by=user,
unified_document=unified_document,
goal_amount=goal_amount,
goal_currency=goal_currency,
status=Fundraise.OPEN,
)
# Create escrow object
escrow = Escrow.objects.create(
created_by=user,
hold_type=Escrow.FUNDRAISE,
content_type=ContentType.objects.get_for_model(Fundraise),
object_id=fundraise.id,
)
fundraise.escrow = escrow
fundraise.save()

return fundraise, None
58 changes: 21 additions & 37 deletions src/purchase/views/fundraise_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from purchase.related_models.constants.currency import RSC, USD
from purchase.serializers.fundraise_serializer import DynamicFundraiseSerializer
from purchase.serializers.purchase_serializer import DynamicPurchaseSerializer
from purchase.utils import create_fundraise_with_escrow
from reputation.models import BountyFee, Escrow
from reputation.utils import calculate_bounty_fees, deduct_bounty_fees
from researchhub_document.models import ResearchhubPost, ResearchhubUnifiedDocument
Expand Down Expand Up @@ -93,18 +94,6 @@ def create(self, request, *args, **kwargs):
# Validate body
if goal_amount is None:
return Response({"message": "goal_amount is required"}, status=400)
try:
goal_amount = decimal.Decimal(goal_amount)
if goal_amount <= 0:
return Response(
{"message": "goal_amount must be greater than 0"}, status=400
)
except Exception as e:
log_error(e)
return Response({"detail": "Invalid goal_amount"}, status=400)
# only allow USD for now
if goal_currency != USD:
return Response({"message": "goal_currency must be USD"}, status=400)
if unified_document_id is None and post_id is None:
return Response(
{"message": "unified_document_id or post_id is required"}, status=400
Expand Down Expand Up @@ -135,19 +124,6 @@ def create(self, request, *args, **kwargs):
unified_document = post.unified_document
except ResearchhubPost.DoesNotExist:
return Response({"message": "Post does not exist"}, status=400)

# Check if there is an existing fundraise for this unified_document
existing_fundraise = Fundraise.objects.filter(
unified_document=unified_document
).first()
if existing_fundraise:
return Response({"message": "Fundraise already exists"}, status=400)
# Must be a preregistration
if unified_document.document_type != PREREGISTRATION:
return Response(
{"message": "Fundraise must be for a preregistration"}, status=400
)

# Get recipient user object
recipient_user = None
if recipient_user_id:
Expand All @@ -160,22 +136,30 @@ def create(self, request, *args, **kwargs):

with transaction.atomic():
# Create fundraise object
fundraise = Fundraise.objects.create(
created_by=recipient_user,
# fundraise = Fundraise.objects.create(
# created_by=recipient_user,
# unified_document=unified_document,
# goal_amount=goal_amount,
# goal_currency=goal_currency,
# status=Fundraise.OPEN,
# )
# # Create escrow object
# escrow = Escrow.objects.create(
# created_by=recipient_user,
# hold_type=Escrow.FUNDRAISE,
# content_type=ContentType.objects.get_for_model(Fundraise),
# object_id=fundraise.id,
# )
# fundraise.escrow = escrow
# fundraise.save()
fundraise, error_response = create_fundraise_with_escrow(
user=recipient_user,
unified_document=unified_document,
goal_amount=goal_amount,
goal_currency=goal_currency,
status=Fundraise.OPEN,
)
# Create escrow object
escrow = Escrow.objects.create(
created_by=recipient_user,
hold_type=Escrow.FUNDRAISE,
content_type=ContentType.objects.get_for_model(Fundraise),
object_id=fundraise.id,
)
fundraise.escrow = escrow
fundraise.save()
if error_response:
return error_response

context = self.get_serializer_context()
serializer = self.get_serializer(fundraise, context=context)
Expand Down
18 changes: 17 additions & 1 deletion src/researchhub_document/views/researchhub_post_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
from hub.models import Hub
from note.related_models.note_model import Note
from purchase.models import Balance, Purchase
from purchase.related_models.constants.currency import USD
from purchase.serializers.fundraise_serializer import DynamicFundraiseSerializer
from purchase.utils import create_fundraise_with_escrow
from researchhub.settings import CROSSREF_DOI_RSC_FEE, TESTING
from researchhub_document.models import ResearchhubPost, ResearchhubUnifiedDocument
from researchhub_document.permissions import HasDocumentEditingPermission
Expand Down Expand Up @@ -168,6 +171,17 @@ def create_researchhub_post(self, request):
rh_post.authors.set(authors)
self.add_upvote(created_by, rh_post)

fundraise = None
if fundraise_data := data.get("fundraise"):
fundraise, error_response = create_fundraise_with_escrow(

Check warning on line 176 in src/researchhub_document/views/researchhub_post_views.py

View check run for this annotation

Codecov / codecov/patch

src/researchhub_document/views/researchhub_post_views.py#L176

Added line #L176 was not covered by tests
user=created_by,
unified_document=unified_document,
goal_amount=fundraise_data.get("goal_amount"),
goal_currency=fundraise_data.get("goal_currency", USD),
)
if error_response:
return error_response

Check warning on line 183 in src/researchhub_document/views/researchhub_post_views.py

View check run for this annotation

Codecov / codecov/patch

src/researchhub_document/views/researchhub_post_views.py#L182-L183

Added lines #L182 - L183 were not covered by tests

if not TESTING:
if document_type in RESEARCHHUB_POST_DOCUMENT_TYPES:
rh_post.discussion_src.save(file_name, full_src_file)
Expand Down Expand Up @@ -202,7 +216,9 @@ def create_researchhub_post(self, request):
)
)

return Response(ResearchhubPostSerializer(rh_post).data, status=200)
response_data = ResearchhubPostSerializer(rh_post).data
response_data["fundraise"] = DynamicFundraiseSerializer(fundraise).data
return Response(response_data, status=200)

except (KeyError, TypeError) as exception:
log_error(exception)
Expand Down

0 comments on commit 08f2c3a

Please sign in to comment.