start creating service transaction

This commit is contained in:
mahdavi 2020-04-20 00:23:15 +04:30
parent 9b4aaec9af
commit 24fd4010c0
5 changed files with 103 additions and 26 deletions

View file

@ -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')),

View file

@ -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()

View file

@ -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

View file

@ -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
)

View file

@ -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