diff --git a/cloud/endagaweb/forms/dashboard_forms.py b/cloud/endagaweb/forms/dashboard_forms.py
index 2f9a6ddc..963616cc 100644
--- a/cloud/endagaweb/forms/dashboard_forms.py
+++ b/cloud/endagaweb/forms/dashboard_forms.py
@@ -367,4 +367,4 @@ def __init__(self, *args, **kwargs):
self.helper.form_method = 'post'
self.helper.form_action = '/dashboard/staff/tower-monitoring'
self.helper.add_input(Submit('submit', 'Select'))
- self.helper.layout = Layout('tower')
+ self.helper.layout = Layout('tower')
\ No newline at end of file
diff --git a/cloud/endagaweb/models.py b/cloud/endagaweb/models.py
index 65b0780f..cadfb72f 100644
--- a/cloud/endagaweb/models.py
+++ b/cloud/endagaweb/models.py
@@ -525,6 +525,7 @@ class Subscriber(models.Model):
# When toggled, this will protect a subsriber from getting "vacuumed." You
# can still delete subs with the usual "deactivate" button.
prevent_automatic_deactivation = models.BooleanField(default=False)
+ valid_through = models.DateTimeField(null=True, auto_now_add=True)
@classmethod
def update_balance(cls, imsi, other_bal):
@@ -978,6 +979,9 @@ class Network(models.Model):
# Network environments let you specify things like "prod", "test", "dev",
# etc so they can be filtered out of alerts. For internal use.
environment = models.TextField(default="default")
+ # Added for Network Balance Limit
+ max_account_limit = models.BigIntegerField(default=10000)
+ max_failure_transaction = models.IntegerField(default=3)
class Meta:
permissions = (
diff --git a/cloud/endagaweb/tasks.py b/cloud/endagaweb/tasks.py
index 405ca698..95774494 100644
--- a/cloud/endagaweb/tasks.py
+++ b/cloud/endagaweb/tasks.py
@@ -17,6 +17,7 @@
import os
import paramiko
import zipfile
+import pytz
try:
# we only import zlib here to check that it is available
# (why would it not be?), so we have to disable the 'unused' warning
@@ -30,6 +31,7 @@
from django.core.mail import send_mail
from django.template.loader import render_to_string
from django.db.models import Avg, Count
+from django.db import transaction
import django.utils.timezone
import requests
@@ -42,6 +44,7 @@
from endagaweb.models import UsageEvent
from endagaweb.models import SystemEvent
from endagaweb.models import TimeseriesStat
+from endagaweb.models import NetworkDenomination
from endagaweb.ic_providers.nexmo import NexmoProvider
@@ -211,11 +214,32 @@ def update_credit(self, imsi, update_id):
url, params={'jwt': jwt},
timeout=settings.ENDAGA['BTS_REQUEST_TIMEOUT_SECS'])
if request.status_code >= 200 and request.status_code < 300:
- print "update_credit SUCCESS. id=%s, imsi=%s, amount=%s. (%d)" % (
- update_id, imsi, update.amount, request.status_code)
- update.delete()
- bts.mark_active()
- bts.save()
+ with transaction.atomic():
+ # Check for existing denomination range exist.
+ denom = NetworkDenomination.objects.filter(
+ start_amount__lte=update.amount,
+ end_amount__gte=update.amount,
+ network=update.subscriber.network).order_by('-end_amount')
+ if len(denom):
+ denom = denom[0]
+ expiry_date = datetime.datetime.now(pytz.UTC) + \
+ datetime.timedelta(days=denom.validity_days)
+ if update.subscriber.valid_through:
+ # Check if existing validity is greater than new validity
+ # then dont update new validity
+ if expiry_date >= update.subscriber.valid_through:
+ update.subscriber.valid_through = expiry_date
+ else:
+ # Check if subscriber has no validity set
+ update.subscriber.valid_through = expiry_date
+
+ update.subscriber.state = 'active'
+ update.subscriber.save()
+ print "update_credit SUCCESS. id=%s, imsi=%s, amount=%s. (%d)"\
+ % (update_id, imsi, update.amount, request.status_code)
+ update.delete()
+ bts.mark_active()
+ bts.save()
else:
message = ("update_credit FAIL. id=%s, imsi=%s, (bts=%s), "
"amount=%s. (%d)")
diff --git a/cloud/endagaweb/templates/dashboard/subscriber_detail/adjust_credit.html b/cloud/endagaweb/templates/dashboard/subscriber_detail/adjust_credit.html
index b2078ef7..ad5e2b57 100644
--- a/cloud/endagaweb/templates/dashboard/subscriber_detail/adjust_credit.html
+++ b/cloud/endagaweb/templates/dashboard/subscriber_detail/adjust_credit.html
@@ -29,7 +29,9 @@
{% for message in messages %}
-
{{ message }}
+
{% endfor %}
diff --git a/cloud/endagaweb/tests/test_denomination.py b/cloud/endagaweb/tests/test_denomination.py
index 71cd6341..d797824f 100644
--- a/cloud/endagaweb/tests/test_denomination.py
+++ b/cloud/endagaweb/tests/test_denomination.py
@@ -8,9 +8,22 @@
of patent rights can be found in the PATENTS file in the same directory.
"""
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
+from datetime import datetime
+from random import randrange
+import uuid
from django import test
+import json
+
+import pytz
+
from django.test import TestCase
+from ccm.common import crdt
from endagaweb import models
diff --git a/cloud/endagaweb/views/dashboard.py b/cloud/endagaweb/views/dashboard.py
index fad4b84e..f05b4185 100644
--- a/cloud/endagaweb/views/dashboard.py
+++ b/cloud/endagaweb/views/dashboard.py
@@ -28,6 +28,7 @@
from django.views.generic import View
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.db.models import Q
+from endagaweb.models import NetworkDenomination
import django_tables2 as tables
import csv
@@ -510,28 +511,30 @@ def get(self, request, imsi=None):
try:
subscriber = Subscriber.objects.get(imsi=imsi,
network=network)
+ # Set the response context.
+ pending_updates = subscriber.pendingcreditupdate_set.all().\
+ order_by('date')
+ initial_form_data = {
+ 'imsi': subscriber.imsi,
+ }
+ context = {
+ 'networks': get_objects_for_user(request.user,
+ 'view_network',
+ klass=Network),
+ 'currency': CURRENCIES[network.subscriber_currency],
+ 'user_profile': user_profile,
+ 'subscriber': subscriber,
+ 'pending_updates': pending_updates,
+ 'credit_update_form': dform.SubscriberCreditUpdateForm(
+ initial=initial_form_data),
+ }
+ # Render template.
+ template = get_template(
+ 'dashboard/subscriber_detail/adjust_credit.html')
+ html = template.render(context, request)
+ return HttpResponse(html)
except Subscriber.DoesNotExist:
- return HttpResponseBadRequest()
- # Set the response context.
- pending_updates = subscriber.pendingcreditupdate_set.all().order_by(
- 'date')
- initial_form_data = {
- 'imsi': subscriber.imsi,
- }
- context = {
- 'networks': get_objects_for_user(request.user, 'view_network', klass=Network),
- 'currency': CURRENCIES[network.subscriber_currency],
- 'user_profile': user_profile,
- 'subscriber': subscriber,
- 'pending_updates': pending_updates,
- 'credit_update_form': dform.SubscriberCreditUpdateForm(
- initial=initial_form_data),
- }
- # Render template.
- template = get_template(
- 'dashboard/subscriber_detail/adjust_credit.html')
- html = template.render(context, request)
- return HttpResponse(html)
+ return dashboard_view(request)
def post(self, request, imsi=None):
"""Operators can use this API to add credit to a subscriber.
@@ -553,23 +556,49 @@ def post(self, request, imsi=None):
# Validate the input.
if 'amount' not in request.POST:
return HttpResponseBadRequest()
- error_text = 'Error: credit value must be between -10M and 10M.'
+ error_text = 'Credit value must be between -10M and 10M.'
+
try:
currency = network.subscriber_currency
amount = parse_credits(request.POST['amount'],
- CURRENCIES[currency]).amount_raw
+ CURRENCIES[currency]).amount_raw
if abs(amount) > 2147483647:
+ error_text = 'Credit value must be between -10M and 10M.'
+ raise ValueError(error_text)
+ if sub.balance + amount > network.max_account_limit:
+ error_text = 'Error : Crossed Credit Limit.'
+ raise ValueError(error_text)
+ try:
+ # Check for existing denomination range exist.
+ denom_exists = NetworkDenomination.objects.filter(
+ start_amount__lte=amount,
+ end_amount__gte=amount,
+ network=network).exists()
+ # Update user validity for recharge denomination amount
+ if denom_exists:
+ try:
+ # Validation suceeded, create a PCU and start the
+ # update credit task.
+ msgid = str(uuid.uuid4())
+ credit_update = PendingCreditUpdate(subscriber=sub,
+ uuid=msgid,
+ amount=amount)
+ credit_update.save()
+ tasks.update_credit.delay(sub.imsi, msgid)
+ return adjust_credit_redirect
+ except Number.DoesNotExist:
+ error_text = 'Subscriber has no number assigned.'
+ raise ValueError(error_text)
+ else:
+ error_text = 'Credit value must be in denomination range.'
+ raise ValueError(error_text)
+ except NetworkDenomination.DoesNotExist:
+ error_text = 'Credit value must be in denomination range.'
raise ValueError(error_text)
except ValueError:
- messages.error(request, error_text)
+ messages.error(request, error_text,
+ extra_tags="alert alert-danger")
return adjust_credit_redirect
- # Validation suceeded, create a PCU and start the update credit task.
- msgid = str(uuid.uuid4())
- credit_update = PendingCreditUpdate(subscriber=sub, uuid=msgid,
- amount=amount)
- credit_update.save()
- tasks.update_credit.delay(sub.imsi, msgid)
- return adjust_credit_redirect
def delete(self, request, imsi=None):
"""Handle the deletion of Pending Credit Updates."""
diff --git a/cloud/endagaweb/views/django_tables.py b/cloud/endagaweb/views/django_tables.py
index fe8daf18..83484d97 100644
--- a/cloud/endagaweb/views/django_tables.py
+++ b/cloud/endagaweb/views/django_tables.py
@@ -364,4 +364,4 @@ def render_action(self, record):
"class='btn btn-xs btn-info'>Edit " % (record.id, record.id)
element += "Delete" % (record.id)
- return safestring.mark_safe(element)
+ return safestring.mark_safe(element)
\ No newline at end of file
diff --git a/cloud/endagaweb/views/network.py b/cloud/endagaweb/views/network.py
index 318335c4..9cb54c29 100644
--- a/cloud/endagaweb/views/network.py
+++ b/cloud/endagaweb/views/network.py
@@ -569,12 +569,12 @@ def post(self, request):
denom = models.NetworkDenomination.objects.get(
id=dnm_id)
# Check for existing denomination range exist.
- denom_exists = \
- models.NetworkDenomination.objects.filter(
- end_amount__gte=start_amount,
- start_amount__lte=end_amount,
- network=user_profile.network).exclude(
- id=dnm_id).count()
+ denom_exists = models.NetworkDenomination.objects.\
+ filter(
+ end_amount__gte=start_amount,
+ start_amount__lte=end_amount,
+ network=user_profile.network).\
+ exclude(id=dnm_id).count()
if denom_exists:
messages.error(
request, 'Denomination range already exists.',