start creating service transaction
This commit is contained in:
parent
9b4aaec9af
commit
24fd4010c0
5 changed files with 103 additions and 26 deletions
|
|
@ -19,7 +19,7 @@ class Migration(migrations.Migration):
|
|||
('code', models.IntegerField(db_index=True, unique=True, verbose_name='code')),
|
||||
('amount', models.IntegerField(verbose_name='amount')),
|
||||
('delay', models.IntegerField(blank=True, default=0)),
|
||||
('state', models.IntegerField(choices=[(1, 'created'), (2, 'delayed'), (3, 'pending'), (4, 'failed'), (5, 'done')], default=1)),
|
||||
('state', models.IntegerField(choices=[(1, 'created'), (2, 'delayed'), (3, 'pending'), (4, 'failed'), (5, 'success')], default=1)),
|
||||
('create', models.DateTimeField(auto_now=True, null=True, verbose_name='create')),
|
||||
('last_update', models.DateTimeField(auto_now=True, null=True, verbose_name='last update')),
|
||||
('application_id', models.IntegerField(blank=True, null=True, verbose_name='application ID')),
|
||||
|
|
|
|||
|
|
@ -8,18 +8,19 @@ from django.utils.translation import gettext_lazy as _
|
|||
from model_utils.choices import Choices
|
||||
from rest_framework.exceptions import APIException, ValidationError
|
||||
|
||||
from apps.users.constans import STATE_CHOICES
|
||||
from apps.users.models import User
|
||||
|
||||
|
||||
class TransactionManager(models.Manager):
|
||||
def create_transaction(self,
|
||||
amount,
|
||||
payee: User,
|
||||
payer: User = None,
|
||||
delay=0,
|
||||
detail_id=None,
|
||||
application_client_id=None,
|
||||
state=None):
|
||||
def create_user_transaction(self,
|
||||
amount,
|
||||
payee: User,
|
||||
payer: User = None,
|
||||
delay=0,
|
||||
detail_id=None,
|
||||
application_client_id=None,
|
||||
state=None):
|
||||
if not (isinstance(payer, User) or payer is None):
|
||||
raise ValidationError('payer type not valid')
|
||||
if not isinstance(payee, User):
|
||||
|
|
@ -42,16 +43,42 @@ class TransactionManager(models.Manager):
|
|||
transaction.save()
|
||||
return transaction
|
||||
|
||||
def create_service_transaction(
|
||||
self,
|
||||
amount,
|
||||
payee: User = None,
|
||||
payer: User = None,
|
||||
# delay=0,
|
||||
detail_id=None,
|
||||
application_client_id=None,
|
||||
# state=None
|
||||
):
|
||||
if not (isinstance(payer, User) or payer is None):
|
||||
raise ValidationError('payer type not valid')
|
||||
if not (isinstance(payee, User) or payee is None):
|
||||
raise ValidationError('payee type not valid')
|
||||
if not amount > 0:
|
||||
raise ValidationError('amount should be greater than zero')
|
||||
# if not delay >= 0:
|
||||
# raise ValidationError('delay should be greater than equal zero')
|
||||
|
||||
transaction = self.model(
|
||||
payer=payer,
|
||||
payee=payee,
|
||||
amount=amount,
|
||||
# delay=delay,
|
||||
detail_id=detail_id,
|
||||
application_client_id=application_client_id,
|
||||
state=STATE_CHOICES.pending
|
||||
)
|
||||
|
||||
transaction.save()
|
||||
return transaction
|
||||
|
||||
|
||||
class Transaction(models.Model):
|
||||
STATE_CHOICES = Choices(
|
||||
(1, 'created', 'created'),
|
||||
(2, 'delayed', 'delayed'),
|
||||
(3, 'pending', 'pending'),
|
||||
(4, 'failed', 'failed'),
|
||||
(5, 'done', 'done'),
|
||||
)
|
||||
uuid = models.UUIDField(primary_key=True, editable=False, default=uuid.uuid4, unique=True, db_index=True) # reserve_code
|
||||
uuid = models.UUIDField(primary_key=True, editable=False, default=uuid.uuid4, unique=True,
|
||||
db_index=True) # reserve_code
|
||||
amount = models.IntegerField(_('amount'), blank=False)
|
||||
delay = models.IntegerField(default=0, blank=True) # number of days for delayed payments
|
||||
payer = models.ForeignKey(User, on_delete=models.PROTECT, related_name='payments', blank=True, null=True)
|
||||
|
|
@ -81,7 +108,7 @@ class Transaction(models.Model):
|
|||
# TODO: check bundry conditions
|
||||
self.last_update = datetime.datetime.now()
|
||||
|
||||
if not self.state == self.STATE_CHOICES.created:
|
||||
if not self.state == STATE_CHOICES.created:
|
||||
raise APIException('this transaction is not ready to pay')
|
||||
|
||||
if self.payer.balance < self.amount:
|
||||
|
|
@ -95,14 +122,14 @@ class Transaction(models.Model):
|
|||
raise APIException('not enough balance')
|
||||
|
||||
if self.delay:
|
||||
self.state = self.STATE_CHOICES.delayed
|
||||
self.state = STATE_CHOICES.delayed
|
||||
self.save()
|
||||
|
||||
else:
|
||||
self.payee.balance = F('balance') + self.amount
|
||||
self.payee.save(update_fields=['balance'])
|
||||
|
||||
self.state = self.STATE_CHOICES.done
|
||||
self.state = STATE_CHOICES.success
|
||||
self.save()
|
||||
|
||||
self.save()
|
||||
|
|
@ -112,11 +139,49 @@ class Transaction(models.Model):
|
|||
with transaction.atomic():
|
||||
self.last_update = datetime.datetime.now()
|
||||
# TODO: check bundry conditions
|
||||
if not self.state == self.STATE_CHOICES.delayed:
|
||||
if not self.state == STATE_CHOICES.delayed:
|
||||
raise APIException('this transaction is not delayed')
|
||||
|
||||
self.payee.balance = F('balance') + self.amount
|
||||
self.state = self.STATE_CHOICES.done
|
||||
self.state = STATE_CHOICES.success
|
||||
self.payee.save()
|
||||
self.save()
|
||||
|
||||
def submit(self):
|
||||
with transaction.atomic():
|
||||
# TODO: check bundry conditions
|
||||
self.last_update = datetime.datetime.now()
|
||||
|
||||
if not self.state == STATE_CHOICES.created:
|
||||
raise APIException('this transaction is not ready to pay')
|
||||
|
||||
if self.payer:
|
||||
self.payer.balance = F('balance') - self.amount
|
||||
self.payer.save(update_fields=['balance'])
|
||||
|
||||
self.payer.refresh_from_db()
|
||||
if self.payer.balance < 0:
|
||||
raise APIException('not enough balance')
|
||||
|
||||
else:
|
||||
self.payee.balance = F('balance') + self.amount
|
||||
self.payee.save(update_fields=['balance'])
|
||||
|
||||
self.state = STATE_CHOICES.success
|
||||
self.save()
|
||||
|
||||
self.save()
|
||||
return self
|
||||
|
||||
def verify(self):
|
||||
with transaction.atomic():
|
||||
self.last_update = datetime.datetime.now()
|
||||
# TODO: check bundry conditions
|
||||
if not self.state == STATE_CHOICES.pending:
|
||||
raise APIException('this transaction is not pending')
|
||||
|
||||
self.payee.balance = F('balance') + self.amount
|
||||
self.state = STATE_CHOICES.success
|
||||
self.payee.save()
|
||||
self.save()
|
||||
|
||||
|
|
|
|||
|
|
@ -34,10 +34,10 @@ class TransactionSerializer(serializers.ModelSerializer):
|
|||
|
||||
if user == payer:
|
||||
with atomic():
|
||||
transaction = Transaction.objects.create_transaction(**validated_data)
|
||||
transaction = Transaction.objects.create_user_transaction(**validated_data)
|
||||
transaction.pay()
|
||||
|
||||
else:
|
||||
transaction = Transaction.objects.create_transaction(**validated_data)
|
||||
transaction = Transaction.objects.create_user_transaction(**validated_data)
|
||||
|
||||
return transaction
|
||||
|
|
|
|||
|
|
@ -1,2 +1,14 @@
|
|||
from model_utils.choices import Choices
|
||||
|
||||
MAX_OTP_TRY = 3
|
||||
DEVELOPMENT_PHONE_NUMBERS = ['+989999999999', '+989999999998']
|
||||
DEVELOPMENT_PHONE_NUMBERS = ['+989999999999', '+989999999998']
|
||||
|
||||
STATE_CHOICES = Choices(
|
||||
(1, 'created', 'created'),
|
||||
(2, 'delayed', 'delayed'), # delayed as user wish
|
||||
(3, 'pending', 'pending'), # wait for external service response
|
||||
(4, 'incomplete', 'incomplete'), # started and wait for internal progress to complete
|
||||
(5, 'success', 'success'),
|
||||
(6, 'failed', 'failed'),
|
||||
(7, 'expected_failure', 'incomplete'), # no exact data available but guessed to be failed
|
||||
)
|
||||
|
|
@ -128,7 +128,7 @@ class ApiClient():
|
|||
path = f'transactions/{uuid}'
|
||||
return self._request(path=path)
|
||||
|
||||
def create_transaction(self, amount, delay, payer=None):
|
||||
def create_user_transaction(self, amount, delay, payer=None):
|
||||
data = {
|
||||
'delay': delay,
|
||||
'amount': amount
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue