1
+ from __future__ import annotations
2
+
1
3
import uuid
2
4
from decimal import Decimal
3
5
from typing import TYPE_CHECKING
4
6
5
- from django .db import IntegrityError , models , transaction
6
- from django .db .models import Max , Sum
7
+ from django .db import models , transaction
8
+ from django .db .models import Sum
7
9
from django .utils .translation import gettext_lazy as _
8
10
9
11
from openforms .plugins .constants import UNIQUE_ID_MAX_LENGTH
14
16
if TYPE_CHECKING :
15
17
from openforms .submissions .models import Submission
16
18
17
- ORDER_ID_START = 100
18
- ORDER_ID_PAD_LENGTH = 6
19
-
20
19
21
- class SubmissionPaymentManager (models .Manager ):
20
+ class SubmissionPaymentManager (models .Manager [ "SubmissionPayment" ] ):
22
21
def create_for (
23
22
self ,
24
- submission : " Submission" ,
23
+ submission : Submission ,
25
24
plugin_id : str ,
26
25
plugin_options : dict ,
27
26
amount : Decimal ,
28
- ):
27
+ ) -> SubmissionPayment :
29
28
assert isinstance (amount , Decimal )
30
29
31
30
# first create without order_id
@@ -36,37 +35,27 @@ def create_for(
36
35
amount = amount ,
37
36
)
38
37
# then update with a unique order_id
39
- while True :
40
- try :
41
- with transaction .atomic ():
42
- payment .order_id = self .get_next_order_id ()
43
- payment .public_order_id = self .create_public_order_id_for (payment )
44
- payment .save (update_fields = ("order_id" , "public_order_id" ))
45
- break
46
- except IntegrityError :
47
- # race condition on unique order_id
48
- continue
49
- return payment
50
38
51
- def get_next_order_id (self ) -> int :
52
- agg = self .aggregate (Max ("order_id" ))
53
- max_order_id = agg ["order_id__max" ] or ORDER_ID_START
54
- return max_order_id + 1
39
+ with transaction .atomic ():
40
+ payment .public_order_id = self .create_public_order_id_for (payment )
41
+ payment .save (update_fields = ("public_order_id" ,))
42
+
43
+ return payment
55
44
56
45
@staticmethod
57
- def create_public_order_id_for (payment : " SubmissionPayment" ) -> str :
46
+ def create_public_order_id_for (payment : SubmissionPayment ) -> str :
58
47
config = GlobalConfiguration .get_solo ()
59
- prefix = config .payment_order_id_prefix
60
- prefix = prefix . replace ( "{year}" , str ( payment . created . year ))
61
- order_id = str ( payment .order_id ). rjust ( ORDER_ID_PAD_LENGTH , "0" )
62
- return prefix + order_id
48
+ prefix = config .payment_order_id_prefix . format ( year = payment . created . year )
49
+ return (
50
+ f" { prefix } _ { payment .submission . public_registration_reference } _ { payment . pk } "
51
+ )
63
52
64
53
65
- class SubmissionPaymentQuerySet (models .QuerySet ):
54
+ class SubmissionPaymentQuerySet (models .QuerySet [ "SubmissionPayment" ] ):
66
55
def sum_amount (self ) -> Decimal :
67
56
return self .aggregate (sum_amount = Sum ("amount" ))["sum_amount" ] or Decimal ("0" )
68
57
69
- def get_completed_public_order_ids (self ) -> list [int ]:
58
+ def get_completed_public_order_ids (self ) -> list [str ]:
70
59
return list (
71
60
self .filter (
72
61
status__in = (PaymentStatus .registered , PaymentStatus .completed )
@@ -88,17 +77,16 @@ class SubmissionPayment(models.Model):
88
77
null = True ,
89
78
help_text = _ ("Copy of payment options at time of initializing payment." ),
90
79
)
91
- order_id = models .BigIntegerField (
92
- _ ("Order ID (internal)" ),
93
- unique = True ,
94
- null = True ,
95
- help_text = _ ("Unique tracking across backend" ),
96
- )
80
+ # TODO Django 5.2 Update to a `GeneratedField`
97
81
public_order_id = models .CharField (
98
82
_ ("Order ID" ),
99
83
max_length = 32 ,
100
84
blank = True ,
101
- help_text = _ ("Order ID stored with payment provider." ),
85
+ help_text = _ (
86
+ "The order ID to be sent to the payment provider. This ID is built by "
87
+ "concatenating an optional global prefix, the submission public reference "
88
+ "and a unique incrementing ID."
89
+ ),
102
90
)
103
91
amount = models .DecimalField (
104
92
_ ("payment amount" ),
@@ -127,8 +115,8 @@ class Meta:
127
115
)
128
116
]
129
117
130
- def __str__ (self ):
131
- return f"#{ self .order_id } '{ self .get_status_display ()} ' { self .amount } "
118
+ def __str__ (self ) -> str :
119
+ return f"#{ self .public_order_id } '{ self .get_status_display ()} ' { self .amount } "
132
120
133
121
@property
134
122
def form (self ):
0 commit comments