Skip to content
This repository has been archived by the owner on Sep 26, 2018. It is now read-only.

Subscriber adjust credit - DO NOT MERGE #40

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cloud/endagaweb/forms/dashboard_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
4 changes: 4 additions & 0 deletions cloud/endagaweb/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does these fields need to be in the PendingCreditUpdate or can we query it from the associated Network ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is depended on PR #38 and part of parent PR

max_failure_transaction = models.IntegerField(default=3)

class Meta:
permissions = (
Expand Down
34 changes: 29 additions & 5 deletions cloud/endagaweb/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

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


Expand Down Expand Up @@ -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)")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
</div>
<div class='col-xs-12'>
{% for message in messages %}
<div class='alert alert-danger message'>{{ message }}</div>
<div class='alert alert-{{ message.tags }} message'>
<a href="#" class="close" data-dismiss="alert">&times;</a>{{ message }}
</div>
{% endfor %}
</div>
</div>
Expand Down
13 changes: 13 additions & 0 deletions cloud/endagaweb/tests/test_denomination.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down
91 changes: 60 additions & 31 deletions cloud/endagaweb/views/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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."""
Expand Down
2 changes: 1 addition & 1 deletion cloud/endagaweb/views/django_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -364,4 +364,4 @@ def render_action(self, record):
"class='btn btn-xs btn-info'>Edit</a> &nbsp; " % (record.id, record.id)
element += "<a href='javascript:void(0)' onclick='doAction(\"delete\",\"%s\");' class='btn btn-xs btn-danger'" \
"data-target='#delete-denom-modal' data-toggle='modal'>Delete</a>" % (record.id)
return safestring.mark_safe(element)
return safestring.mark_safe(element)
12 changes: 6 additions & 6 deletions cloud/endagaweb/views/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.',
Expand Down