Make Kassa communicate with Dusken.
This commit is contained in:
1 parent
f400d7a295
commit
031a400855
21 files changed
+14731
-7321
No files matched your search
@@ -12,7 +12,22 @@ Kassa helps you register purchased membership cards and memberships. It's a tool
|
||||
pip install -r requirements.txt
|
||||
python manage.py migrate
|
||||
|
||||
### LDAP
|
||||
## Configuration
|
||||
Create a user in Dusken with the following permissions:
|
||||
* dusken | User | Can view User
|
||||
* dusken | Member card | Can change Member card
|
||||
* dusken | Member card | Can view Member card
|
||||
* dusken | Membership | Can add Membership
|
||||
* dusken | Membership | Can view Membership
|
||||
* dusken | Order | Can view Order
|
||||
|
||||
Fetch DUSKEN_API_KEY:
|
||||
curl -H "Content-Type: application/json" -X POST -d '{"username":"apiuser","password":"test"}' DUSKEN_API_URL/auth/obtain-token/
|
||||
|
||||
If developing you can disable calls to Tekstmelding in local_settings.py:
|
||||
TEKSTMELDING_ENABLED = False
|
||||
|
||||
## LDAP
|
||||
sudo docker run -e LDAP_DOMAIN=neuf.no -e LDAP_ORGANISATION="Neuf" -e LDAP_ADMIN_PASSWORD="toor" -p 389:389 -d nikolaik/openldap
|
||||
ldapadd -D "cn=admin,dc=neuf,dc=no" -w "toor" -f test/testdata.ldif # Testdata
|
||||
# Verify import
|
||||
|
||||
+4
-2
@@ -3,8 +3,10 @@ from django.contrib import admin
|
||||
|
||||
|
||||
class KassaEventAdmin(admin.ModelAdmin):
|
||||
list_display = ['id', 'event', 'card_number', 'user_phone_number', 'user_inside_id', 'created']
|
||||
list_display = ['id', 'event', 'card_number', 'user_phone_number', 'user_dusken_id',
|
||||
'user_inside_id', 'created', 'transaction_id']
|
||||
list_filter = ['event']
|
||||
search_fields = ['card_number', 'user_phone_number', 'user_inside_id']
|
||||
search_fields = ['card_number', 'user_phone_number', 'user_dusken_id',
|
||||
'user_inside_id', 'transaction_id']
|
||||
|
||||
admin.site.register(KassaEvent, KassaEventAdmin)
|
||||
@@ -14,3 +14,4 @@ class AddCardForm(forms.Form):
|
||||
card_number = forms.IntegerField(widget=forms.NumberInput(attrs={'autofocus': True}))
|
||||
phone_number = PhoneNumberField(widget=forms.TextInput(attrs={'type': 'tel'}))
|
||||
user_id = forms.IntegerField(widget=forms.HiddenInput(), required=False)
|
||||
order_uuid = forms.IntegerField(widget=forms.HiddenInput(), required=False)
|
||||
@@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.3 on 2017-07-22 12:40
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('kassa', '0006_auto_20150829_1811'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='kassaevent',
|
||||
name='transaction_id',
|
||||
field=models.UUIDField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.3 on 2017-07-22 12:43
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('kassa', '0007_kassaevent_transaction_id'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='kassaevent',
|
||||
name='user_dusken_id',
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -21,7 +21,9 @@ class KassaEvent(models.Model):
|
||||
)
|
||||
event = models.CharField(max_length=255, choices=EVENT_CHOICES)
|
||||
card_number = models.IntegerField(null=True, blank=True)
|
||||
user_dusken_id = models.IntegerField(null=True, blank=True)
|
||||
user_inside_id = models.IntegerField(null=True, blank=True)
|
||||
user_phone_number = models.CharField(max_length=100, null=True, blank=True)
|
||||
transaction_id = models.UUIDField(null=True, blank=True)
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
updated = models.DateTimeField(auto_now=True)
|
||||
@@ -18,7 +18,7 @@
|
||||
{{ add_card_form|bootstrap }}
|
||||
<div class="register-card-form--selected-user-section">
|
||||
<label>{% trans "Member" %}</label>
|
||||
<div class="register-card-form--selected-user-wrap"></div>
|
||||
<div class="register-card-form--selected-entity-wrap"></div>
|
||||
</div>
|
||||
|
||||
<button id="register-submit-btn" type="submit" class="btn btn-primary btn-lg" disabled>{% trans "Register card" %}</button>
|
||||
|
||||
+6
-5
@@ -1,12 +1,13 @@
|
||||
from django.conf.urls import url
|
||||
from apps.kassa.views import register, inside_user_api, inside_card_api, check_phone_number, \
|
||||
register_card_and_membership, stats_card_sales, renew_membership
|
||||
from apps.kassa.views import (register, user_search, check_card,
|
||||
check_phone_number, register_card_and_membership,
|
||||
stats_card_sales, renew_membership)
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', register, name='register'),
|
||||
url(r'^inside/user/$', inside_user_api, name='inside-user-api'),
|
||||
url(r'^check-phonenumber/$', check_phone_number, name='check-phone-number'),
|
||||
url(r'^inside/card/$', inside_card_api, name='inside-card-number-api'),
|
||||
url(r'^user-search/$', user_search, name='user-search'),
|
||||
url(r'^check-phone-number/$', check_phone_number, name='check-phone-number'),
|
||||
url(r'^check-card/$', check_card, name='check-card'),
|
||||
url(r'^register-card-membership/$', register_card_and_membership, name='register-card-and-membership'),
|
||||
url(r'^renew-membership/$', renew_membership, name='renew-membership'),
|
||||
url(r'^stats/card-sales/$', stats_card_sales, name='stats-card-sales')
|
||||
|
||||
+68
-36
@@ -3,6 +3,13 @@ from django.conf import settings
|
||||
import datetime
|
||||
import phonenumbers
|
||||
import requests
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
dusken_auth = {
|
||||
'Authorization': 'Token {}'.format(settings.DUSKEN_API_KEY)
|
||||
}
|
||||
|
||||
|
||||
def tekstmelding_new_membership_card(card_number, phone_number):
|
||||
@@ -12,6 +19,10 @@ def tekstmelding_new_membership_card(card_number, phone_number):
|
||||
'action': 'new_card_no_user',
|
||||
}
|
||||
|
||||
if not settings.TEKSTMELDING_ENABLED:
|
||||
logger.info('Tekstmelding disabled. Payload would be: ', payload)
|
||||
return
|
||||
|
||||
url = '{}kassa/new-membership-card'.format(settings.TEKSTMELDING_API_URL)
|
||||
response = requests.post(
|
||||
url,
|
||||
@@ -23,48 +34,69 @@ def tekstmelding_new_membership_card(card_number, phone_number):
|
||||
return response.json()
|
||||
|
||||
|
||||
def inside_get_card(card_number):
|
||||
url = '{}card.php'.format(settings.INSIDE_API_URL)
|
||||
params = {
|
||||
'apikey': settings.INSIDE_API_KEY,
|
||||
'card_number': card_number
|
||||
}
|
||||
|
||||
return requests.get(url, params=params)
|
||||
def get_card(card_number):
|
||||
url = '{}cards/{}/'.format(settings.DUSKEN_API_URL, card_number)
|
||||
return requests.get(url, headers=dusken_auth)
|
||||
|
||||
|
||||
def inside_update_card(card_number, user_id, phone_number, action, membership_trial=None):
|
||||
url = '{}card.php'.format(settings.INSIDE_API_URL)
|
||||
def get_order(order_uuid):
|
||||
url = '{}orders/{}/'.format(settings.DUSKEN_API_URL, order_uuid)
|
||||
return requests.get(url, headers=dusken_auth)
|
||||
|
||||
|
||||
def get_latest_order_by_card(card_number):
|
||||
url = '{}orders/'.format(settings.DUSKEN_API_URL)
|
||||
payload = {'card_number': card_number}
|
||||
orders = requests.get(url, params=payload, headers=dusken_auth).json()
|
||||
return orders.get('results')[0]
|
||||
|
||||
|
||||
def get_latest_order_by_phone(phone_number):
|
||||
url = '{}orders/'.format(settings.DUSKEN_API_URL)
|
||||
payload = {'phone_number': phone_number}
|
||||
orders = requests.get(url, params=payload, headers=dusken_auth).json()
|
||||
if orders.get('count'):
|
||||
return orders.get('results')[0]
|
||||
return None
|
||||
|
||||
|
||||
def get_user(user_id):
|
||||
url = '{}users/{}/'.format(settings.DUSKEN_API_URL, user_id)
|
||||
return requests.get(url, headers=dusken_auth)
|
||||
|
||||
|
||||
def get_user_by_phone(phone_number):
|
||||
url = '{}users/'.format(settings.DUSKEN_API_URL)
|
||||
payload = {'phone_number': phone_number}
|
||||
users = requests.get(url, params=payload, headers=dusken_auth).json()
|
||||
if users.get('count') == 1:
|
||||
return users.get('results')[0]
|
||||
return None
|
||||
|
||||
|
||||
def update_card(card_number, user_id=None, order_uuid=None):
|
||||
assert not (user_id and order_uuid)
|
||||
url = '{}kassa/card/'.format(settings.DUSKEN_API_URL)
|
||||
payload = {
|
||||
'card_number': card_number,
|
||||
'user_id': user_id,
|
||||
'member_card': card_number,
|
||||
'user': user_id,
|
||||
'order': order_uuid,
|
||||
}
|
||||
return requests.patch(url, json=payload, headers=dusken_auth)
|
||||
|
||||
|
||||
def update_membership(user=None, phone_number=None, card_number=None, membership_type=None,
|
||||
transaction_id=None):
|
||||
assert membership_type in ('standard', 'trial')
|
||||
url = '{}kassa/membership/'.format(settings.DUSKEN_API_URL)
|
||||
payload = {
|
||||
'user': user,
|
||||
'phone_number': phone_number,
|
||||
'action': action # new_card_membership, update_card, add_or_renew, sms_card_notify
|
||||
'member_card': card_number,
|
||||
'membership_type': membership_type,
|
||||
'transaction_id': transaction_id,
|
||||
}
|
||||
if membership_trial is not None:
|
||||
payload.update({'membership_trial': membership_trial})
|
||||
|
||||
return requests.post(
|
||||
url,
|
||||
json=payload,
|
||||
params={'apikey': settings.INSIDE_API_KEY},
|
||||
headers=dict(content_type='application/json')
|
||||
)
|
||||
|
||||
|
||||
def inside_update_membership(user_id, purchased=None, membership_trial=None):
|
||||
url = '{}membership.php'.format(settings.INSIDE_API_URL)
|
||||
payload = {
|
||||
'apikey': settings.INSIDE_API_KEY,
|
||||
'user_id': user_id,
|
||||
'purchased': purchased,
|
||||
'source': 'kassa'
|
||||
}
|
||||
if membership_trial is not None:
|
||||
payload.update({'membership_trial': membership_trial})
|
||||
|
||||
return requests.post(url, json=payload, headers=dict(content_type='application/json'))
|
||||
return requests.post(url, json=payload, headers=dusken_auth)
|
||||
|
||||
|
||||
def format_phone_number(number):
|
||||
|
||||
+84
-70
@@ -6,14 +6,16 @@ from django.shortcuts import render
|
||||
from django.utils import timezone
|
||||
from itertools import groupby
|
||||
import json
|
||||
import uuid
|
||||
import logging
|
||||
import phonenumbers
|
||||
import requests
|
||||
|
||||
from apps.kassa.models import KassaEvent
|
||||
from apps.kassa.forms import AddCardForm, SearchUserForm
|
||||
from apps.kassa.utils import tekstmelding_new_membership_card, inside_update_card, inside_get_card, \
|
||||
inside_update_membership, format_phone_number, is_autumn
|
||||
from apps.kassa.utils import tekstmelding_new_membership_card, update_card, get_card, \
|
||||
get_order, get_latest_order_by_card, get_latest_order_by_phone, get_user, get_user_by_phone, \
|
||||
dusken_auth, update_membership, format_phone_number, is_autumn
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -29,18 +31,17 @@ def register(request):
|
||||
|
||||
|
||||
@login_required
|
||||
def inside_user_api(request):
|
||||
def user_search(request):
|
||||
payload = {
|
||||
'apikey': settings.INSIDE_API_KEY,
|
||||
'q': request.GET.get('q', '')
|
||||
'search': request.GET.get('search', '')
|
||||
}
|
||||
url = '{}user.php'.format(settings.INSIDE_API_URL)
|
||||
data = requests.get(url, params=payload).json()
|
||||
url = '{}users/'.format(settings.DUSKEN_API_URL)
|
||||
data = requests.get(url, params=payload, headers=dusken_auth).json()
|
||||
|
||||
return JsonResponse(data)
|
||||
|
||||
|
||||
@login_required()
|
||||
@login_required
|
||||
def check_phone_number(request):
|
||||
number = request.GET.get('phone_number', '').strip()
|
||||
|
||||
@@ -56,115 +57,128 @@ def check_phone_number(request):
|
||||
return JsonResponse({'error': str(e).replace('(1) ', '')})
|
||||
|
||||
number = phonenumbers.format_number(p, phonenumbers.PhoneNumberFormat.E164)
|
||||
|
||||
# Inside lookup existing user
|
||||
payload = {
|
||||
'apikey': settings.INSIDE_API_KEY,
|
||||
'q': number
|
||||
}
|
||||
url = '{}phonenumber.php'.format(settings.INSIDE_API_URL)
|
||||
inside_data = requests.get(url, params=payload).json()
|
||||
|
||||
# Tekstmelding lookup pending memberships
|
||||
payload = {
|
||||
'api_key': settings.TEKSTMELDING_API_KEY,
|
||||
'number': number
|
||||
}
|
||||
url = '{}kassa/pending-membership'.format(settings.TEKSTMELDING_API_URL)
|
||||
tekstmelding_data = requests.get(url, params=payload).json()
|
||||
user = get_user_by_phone(number)
|
||||
order = get_latest_order_by_phone(number)
|
||||
|
||||
return JsonResponse({
|
||||
'tekstmelding': tekstmelding_data,
|
||||
'inside': inside_data
|
||||
'user': user,
|
||||
'order': order
|
||||
})
|
||||
|
||||
|
||||
@login_required
|
||||
def inside_card_api(request):
|
||||
def check_card(request):
|
||||
if request.method != 'GET':
|
||||
return JsonResponse({'error': 'Only method GET supported'})
|
||||
|
||||
response = inside_get_card(request.GET.get('card_number'))
|
||||
return JsonResponse(response.json(), status=response.status_code)
|
||||
card_number = request.GET.get('card_number')
|
||||
response = get_card(card_number)
|
||||
if response.status_code != 200:
|
||||
return JsonResponse(response.json(), status=response.status_code)
|
||||
card = response.json()
|
||||
if card.get('user'):
|
||||
card['user'] = get_user(card['user']).json()
|
||||
card['order'] = None
|
||||
if card.get('orders'):
|
||||
card['order'] = get_latest_order_by_card(card_number)
|
||||
card.pop('orders')
|
||||
return JsonResponse(card, status=response.status_code)
|
||||
|
||||
|
||||
@login_required()
|
||||
@login_required
|
||||
def register_card_and_membership(request):
|
||||
if request.method != 'POST':
|
||||
return JsonResponse({'error': 'Only method POST supported'})
|
||||
|
||||
post_data = json.loads(request.body.decode('utf-8'))
|
||||
action = post_data.get('action') # new_card_membership, update_card, add_or_renew, sms_card_notify
|
||||
# new_card_membership, update_card, add_or_renew, sms_card_notify
|
||||
# TODO: multiple actions (to allow renewal only)
|
||||
action = post_data.get('action')
|
||||
user_id = post_data.get('user_id')
|
||||
order_uuid = post_data.get('order_uuid')
|
||||
card_number = post_data.get('card_number')
|
||||
phone_number = post_data.get('phone_number')
|
||||
membership_trial = post_data.get('membership_trial')
|
||||
membership_type = 'trial' if membership_trial else 'standard'
|
||||
|
||||
response = inside_update_card(
|
||||
card_number,
|
||||
user_id,
|
||||
post_data.get('phone_number'),
|
||||
action,
|
||||
membership_trial
|
||||
)
|
||||
if response.status_code != 200:
|
||||
return JsonResponse(response.json(), status=response.status_code)
|
||||
# Update card number on user or order
|
||||
if action in ('update_card', 'sms_card_notify'):
|
||||
if action == 'update_card' and user_id:
|
||||
response = update_card(card_number, user_id=user_id)
|
||||
elif action == 'sms_card_notify' and order_uuid:
|
||||
response = update_card(card_number, order_uuid=order_uuid)
|
||||
else:
|
||||
assert user_id or order_uuid
|
||||
if response.status_code != 200:
|
||||
return JsonResponse(response.json(), status=response.status_code)
|
||||
|
||||
event_data = {
|
||||
'event': KassaEvent.UPDATE_CARD,
|
||||
'user_phone_number': format_phone_number(post_data.get('phone_number')),
|
||||
'card_number': card_number
|
||||
}
|
||||
if user_id:
|
||||
event_data.update({'user_inside_id': user_id})
|
||||
event_data = {
|
||||
'event': KassaEvent.UPDATE_CARD,
|
||||
'user_phone_number': phone_number,
|
||||
'card_number': card_number,
|
||||
'user_dusken_id': user_id,
|
||||
}
|
||||
logger.debug(event_data)
|
||||
KassaEvent.objects.create(**event_data)
|
||||
|
||||
logger.debug(event_data)
|
||||
|
||||
KassaEvent.objects.create(**event_data)
|
||||
|
||||
card_update_response = response.json()
|
||||
# Add initial or renew membership for existing user or order
|
||||
if action in ('add_or_renew', 'new_card_membership'):
|
||||
transaction_id = uuid.uuid4()
|
||||
response = update_membership(
|
||||
user=user_id,
|
||||
phone_number=phone_number,
|
||||
card_number=card_number,
|
||||
membership_type=membership_type,
|
||||
transaction_id=str(transaction_id))
|
||||
KassaEvent.objects.create(
|
||||
event=KassaEvent.ADD_OR_RENEW if membership_type != 'trial' else KassaEvent.MEMBERSHIP_TRIAL,
|
||||
user_dusken_id=user_id,
|
||||
card_number=card_number,
|
||||
user_phone_number=phone_number,
|
||||
transaction_id=transaction_id
|
||||
)
|
||||
|
||||
# Send activation notification (link) to user by SMS
|
||||
if action == 'new_card_membership' or action == 'sms_card_notify':
|
||||
card = card_update_response['card']
|
||||
if action in ('new_card_membership', 'sms_card_notify'):
|
||||
event = KassaEvent.NEW_CARD_MEMBERSHIP
|
||||
if action == 'sms_card_notify':
|
||||
event = KassaEvent.SMS_CARD_NOTIFY
|
||||
elif event == KassaEvent.NEW_CARD_MEMBERSHIP and membership_trial is not None:
|
||||
event = KassaEvent.MEMBERSHIP_TRIAL
|
||||
|
||||
# FIXME: could be async
|
||||
tekstmelding_new_membership_card(card_number=card['card_number'], phone_number=card['owner_phone_number'])
|
||||
tekstmelding_new_membership_card(card_number=card_number,
|
||||
phone_number=phone_number)
|
||||
KassaEvent.objects.create(
|
||||
event=event,
|
||||
card_number=card['card_number'],
|
||||
user_phone_number=card['owner_phone_number']
|
||||
)
|
||||
|
||||
# Add initial or renew membership for existing user
|
||||
elif action == 'add_or_renew':
|
||||
response = inside_update_membership(user_id, post_data.get('purchased'), membership_trial=membership_trial)
|
||||
KassaEvent.objects.create(
|
||||
event=KassaEvent.ADD_OR_RENEW if membership_trial is None else KassaEvent.MEMBERSHIP_TRIAL,
|
||||
user_inside_id=user_id
|
||||
card_number=card_number,
|
||||
user_phone_number=phone_number
|
||||
)
|
||||
|
||||
return JsonResponse(response.json(), status=response.status_code)
|
||||
|
||||
|
||||
@login_required()
|
||||
@login_required
|
||||
def renew_membership(request):
|
||||
if request.method != 'POST':
|
||||
return JsonResponse({'error': 'Only method POST supported'})
|
||||
|
||||
post_data = json.loads(request.body.decode('utf-8'))
|
||||
user_id = post_data.get('user_id')
|
||||
phone_number = post_data.get('phone_number')
|
||||
card_number = post_data.get('card_number')
|
||||
membership_trial = post_data.get('membership_trial')
|
||||
membership_type = 'trial' if membership_trial else 'standard'
|
||||
transaction_id = str(uuid.uuid4())
|
||||
|
||||
response = inside_update_membership(user_id, purchased=post_data.get('purchased'), membership_trial=membership_trial)
|
||||
response = update_membership(
|
||||
user=user_id,
|
||||
phone_number=phone_number,
|
||||
card_number=card_number,
|
||||
membership_type=membership_type,
|
||||
transaction_id=transaction_id)
|
||||
KassaEvent.objects.create(
|
||||
event=KassaEvent.RENEW_ONLY if membership_trial is None else KassaEvent.MEMBERSHIP_TRIAL,
|
||||
user_inside_id=user_id
|
||||
user_dusken_id=user_id,
|
||||
transaction_id=transaction_id
|
||||
)
|
||||
|
||||
return JsonResponse(response.json(), status=response.status_code)
|
||||
|
||||
@@ -113,11 +113,12 @@ STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
|
||||
|
||||
LOGIN_REDIRECT_URL = '/'
|
||||
|
||||
INSIDE_API_KEY = ''
|
||||
INSIDE_API_URL = 'https://inside.studentersamfundet.no/api/'
|
||||
DUSKEN_API_KEY = ''
|
||||
DUSKEN_API_URL = 'https://dusken.neuf.no/api/'
|
||||
|
||||
TEKSTMELDING_API_KEY = ''
|
||||
TEKSTMELDING_API_URL = 'https://tekstmelding.neuf.no/'
|
||||
TEKSTMELDING_ENABLED = True
|
||||
|
||||
CORS_ORIGIN_ALLOW_ALL = True
|
||||
|
||||
|
||||
+185
-123
@@ -20,20 +20,7 @@ function getParameterByName(name) {
|
||||
results = regex.exec(location.search);
|
||||
return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
|
||||
}
|
||||
function update_user_with_card_details(user) {
|
||||
/* Cards with a number lower than this is legacy as of 2015-08 */
|
||||
var legacy_card_limit = 100000000;
|
||||
|
||||
for(var j=0; j<user.cards.length; j++) {
|
||||
if(parseInt(user.cards[j].card_number, 10) < legacy_card_limit) {
|
||||
user.cards[j].is_legacy = "1";
|
||||
}
|
||||
if(user.cards[j].is_active == "1") {
|
||||
user.card_number_active = user.cards[j].card_number;
|
||||
}
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
function format_phone_number(str) {
|
||||
if(!str || str.length <= 1) {
|
||||
@@ -46,20 +33,36 @@ function format_phone_number(str) {
|
||||
return str;
|
||||
}
|
||||
|
||||
function sort_search_results(results) {
|
||||
return _.sortBy(results, function (x) {
|
||||
if (x.last_membership) {
|
||||
if (x.last_membership.end_date) {
|
||||
return 0 - moment(x.last_membership.end_date).unix();
|
||||
}
|
||||
return 0 - moment(x.last_membership.start_date).unix();
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
function format_results(results) {
|
||||
results = _.map(results, update_user_with_card_details);
|
||||
return nunjucksEnv.render('search_results.html', {'results': results});
|
||||
}
|
||||
function render_selected_user(user_data) {
|
||||
var context;
|
||||
if(user_data === undefined || user_data === null) {
|
||||
if (!user_data) {
|
||||
context = {placeholder: true}; // dummy card
|
||||
} else {
|
||||
user_data = update_user_with_card_details(user_data);
|
||||
context = {res: user_data, checked: true, no_user_actions: true};
|
||||
}
|
||||
var selected_user_html = nunjucksEnv.render('search_result.html', context);
|
||||
_dom.selectedUserWrap.html(selected_user_html);
|
||||
_dom.selectedEntityWrap.html(selected_user_html);
|
||||
}
|
||||
function render_selected_order(order) {
|
||||
if (!order) { return; }
|
||||
var context = {order: order, checked: true, no_user_actions: true};
|
||||
var selected_order_html = nunjucksEnv.render('selected_order.html', context);
|
||||
_dom.selectedEntityWrap.html(selected_order_html);
|
||||
}
|
||||
function set_toast(message, message_type) {
|
||||
var context = {
|
||||
@@ -76,15 +79,9 @@ function set_toast(message, message_type) {
|
||||
}
|
||||
function set_selected_user(user, update_search_result) {
|
||||
selectedUser = user;
|
||||
var new_val = '';
|
||||
updateMemberShipButton(user, null);
|
||||
|
||||
if(user) {
|
||||
new_val = user.id;
|
||||
}
|
||||
|
||||
updateMemberShipButton(user);
|
||||
|
||||
_dom.userIdField.val(new_val).trigger('change');
|
||||
_dom.userIdField.val((user && user.id) || '').trigger('change');
|
||||
if(update_search_result) {
|
||||
var stale_search_result = _dom.results.find('.search-result').removeClass('selected');
|
||||
stale_search_result.find('input').prop('checked', false);
|
||||
@@ -95,6 +92,13 @@ function set_selected_user(user, update_search_result) {
|
||||
}
|
||||
}
|
||||
}
|
||||
function set_selected_order(order) {
|
||||
membershipOrder = order;
|
||||
if (order) {
|
||||
updateMemberShipButton(null, order);
|
||||
}
|
||||
_dom.orderUuidField.val((order && order.uuid) || '').trigger('change');
|
||||
}
|
||||
|
||||
function set_field_state(field_element, state, help_text) {
|
||||
if(!help_text) {
|
||||
@@ -140,12 +144,10 @@ function resetCardForm(reset_native) {
|
||||
set_field_state(_dom.cardNumberField, '');
|
||||
cardForm.fields.cardNumber = false;
|
||||
selectedUser = null;
|
||||
membershipOrder = null;
|
||||
_dom.userIdField.val('').trigger('change');
|
||||
|
||||
_dom.membershipTrialCheckBox.prop('checked', false);
|
||||
|
||||
pendingSMSMembership = null;
|
||||
|
||||
/* Disable submit buttons */
|
||||
_dom.registerSubmitButton.prop('disabled', true);
|
||||
_dom.membershipSubmitButton.prop('disabled', true);
|
||||
@@ -170,16 +172,34 @@ function update_submit_button() {
|
||||
}
|
||||
_dom.registerSubmitButton.prop('disabled', true);
|
||||
}
|
||||
function updateMemberShipButton(user) {
|
||||
var today_plus_one_month = moment().add(1, 'month').format('YYYY-MM-DD');
|
||||
/* Existing member with upcoming expiry and card */
|
||||
if(user && user.is_member === '1' && user.expires <= today_plus_one_month && user.card_number_active !== '') {
|
||||
function updateMemberShipButton(user, order) {
|
||||
var today_plus_thirty_days = moment().add(30, 'days').format('YYYY-MM-DD');
|
||||
/* User with valid membership */
|
||||
if (user && user.is_member) {
|
||||
/* ...which is lifelong cannot renew */
|
||||
if (user.last_membership.membership_type == 'lifelong') {
|
||||
_dom.membershipSubmitButton.prop('disabled', true);
|
||||
}
|
||||
/* ...or expiring soon and the user has a card */
|
||||
//else if (user.last_membership.end_date <= today_plus_thirty_days && user.active_member_card) {
|
||||
/* ...with a membership that expires soon can renew */
|
||||
else if (user.last_membership.end_date <= today_plus_thirty_days) {
|
||||
_dom.membershipSubmitButton.prop('enabled', false);
|
||||
}
|
||||
}
|
||||
/* User with expired membership can renew */
|
||||
// else if (user && !user.is_member && user.active_member_card) {
|
||||
else if (user && !user.is_member) {
|
||||
_dom.membershipSubmitButton.prop('disabled', false);
|
||||
}
|
||||
/* User with card, but expired membership */
|
||||
else if(user && user.is_member !== '1' && user.card_number_active !== '') {
|
||||
_dom.membershipSubmitButton.prop('disabled', false);
|
||||
} else {
|
||||
/* Order */
|
||||
else if (order) {
|
||||
/* If the membership has expired it can be renewed */
|
||||
if (!order.product.is_valid && order.product.end_date <= today_plus_thirty_days) {
|
||||
_dom.membershipSubmitButton.prop('disabled', false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
_dom.membershipSubmitButton.prop('disabled', true);
|
||||
}
|
||||
}
|
||||
@@ -187,7 +207,7 @@ function validatePhoneNumber(val) {
|
||||
if(val.length === 0) {
|
||||
cardForm.fields.phoneNumber = false;
|
||||
update_submit_button();
|
||||
return 'Phonenumber number should not be empty.';
|
||||
return 'Phone number should not be empty.';
|
||||
}
|
||||
cardForm.fields.phoneNumber = true;
|
||||
update_submit_button();
|
||||
@@ -204,11 +224,11 @@ function validateCardNumber(val) {
|
||||
cardForm.fields.cardNumber = false;
|
||||
update_submit_button();
|
||||
return 'Card number should start with 1.';
|
||||
}
|
||||
}
|
||||
if(val.length !== 9) {
|
||||
cardForm.fields.cardNumber = false;
|
||||
update_submit_button();
|
||||
return 'Card number should be 9 digits long';
|
||||
return 'Card number should be 9 digits long.';
|
||||
}
|
||||
cardForm.fields.cardNumber = true;
|
||||
update_submit_button();
|
||||
@@ -218,8 +238,10 @@ function validateCardNumber(val) {
|
||||
function getFormData(formElement) {
|
||||
var formData = formElement.serializeArray();
|
||||
formData = _.object(_.map(formData, function (x) {
|
||||
return [x.name, x.value];
|
||||
return [x.name, x.value || null];
|
||||
}));
|
||||
/* no need for radio button state */
|
||||
delete formData.user;
|
||||
|
||||
return formData;
|
||||
}
|
||||
@@ -231,44 +253,50 @@ function checkPhoneNumber() {
|
||||
/* Invalid phone number?*/
|
||||
if(data.error) {
|
||||
set_selected_user(null, true);
|
||||
set_selected_order(null);
|
||||
set_field_state(_dom.phoneNumberField, 'error', data.error);
|
||||
cardForm.fields.phoneNumber = false;
|
||||
pendingSMSMembership = null;
|
||||
update_submit_button();
|
||||
return;
|
||||
}
|
||||
/* Already has valid card membership? */
|
||||
if(data.inside.card && data.inside.card.has_valid_membership == "1") {
|
||||
var card = data.inside.card;
|
||||
var msg = 'Phone number is already tied to card '+ card.card_number + ' and is valid until '+ card.expires +'.';
|
||||
set_field_state(_dom.phoneNumberField, 'error', msg);
|
||||
|
||||
var user = data.user;
|
||||
var order = data.order;
|
||||
var message = '';
|
||||
|
||||
/* Has valid card membership */
|
||||
if (!user && order && order.member_card && order.product.is_valid) {
|
||||
message = 'Phone number is already tied to card '+ order.member_card + ' and is valid until '+ order.product.end_date +'.';
|
||||
set_field_state(_dom.phoneNumberField, 'error', message);
|
||||
cardForm.fields.phoneNumber = false;
|
||||
pendingSMSMembership = null;
|
||||
set_selected_order(order);
|
||||
update_submit_button();
|
||||
return;
|
||||
}
|
||||
|
||||
var inside = data.inside;
|
||||
var tekstmelding = data.tekstmelding;
|
||||
var _user = null;
|
||||
var _success_msg = '';
|
||||
|
||||
if(inside.users.length == 1) {
|
||||
if (user) {
|
||||
/* Existing user */
|
||||
_user = inside.users[0];
|
||||
_success_msg = 'Phone number belongs to existing user.';
|
||||
pendingSMSMembership = null;
|
||||
} else if(tekstmelding.result !== null) {
|
||||
/* Pending SMS membership (not activated yet) */
|
||||
_success_msg = 'Phone number has valid membership (paid via SMS). OK to give out card.';
|
||||
pendingSMSMembership = tekstmelding.result;
|
||||
message = 'Phone number belongs to existing user.';
|
||||
set_field_state(_dom.phoneNumberField, 'success', message);
|
||||
set_selected_user(user, true);
|
||||
set_selected_order(null);
|
||||
cardForm.fields.phoneNumber = true;
|
||||
update_submit_button();
|
||||
} else if (order) {
|
||||
set_selected_order(order);
|
||||
/* Valid membership, no card associated */
|
||||
if (order.product.is_valid) {
|
||||
message = 'Phone number has a valid membership.';
|
||||
} else {
|
||||
message = 'Phone number has an expired membership.';
|
||||
}
|
||||
} else {
|
||||
/* Valid phone number with no existing user, card membership or pending SMS membership */
|
||||
pendingSMSMembership = null;
|
||||
/* Valid phone number associated user or order */
|
||||
set_selected_order(null);
|
||||
set_selected_user(null);
|
||||
}
|
||||
|
||||
set_field_state(_dom.phoneNumberField, 'success', _success_msg);
|
||||
set_selected_user(_user, true);
|
||||
set_field_state(_dom.phoneNumberField, 'success', message);
|
||||
cardForm.fields.phoneNumber = true;
|
||||
update_submit_button();
|
||||
});
|
||||
@@ -277,8 +305,9 @@ function checkPhoneNumber() {
|
||||
/* Init and global vars */
|
||||
var _dom;
|
||||
var users;
|
||||
var searching; /* search ajax request */
|
||||
var selectedUser;
|
||||
var pendingSMSMembership;
|
||||
var membershipOrder; /* selected order object */
|
||||
var cardForm = {
|
||||
fields: {
|
||||
cardNumber: false,
|
||||
@@ -295,9 +324,9 @@ var nunjucksEnv = new nunjucks.Environment();
|
||||
nunjucksEnv.addFilter('phoneNumber', format_phone_number);
|
||||
|
||||
var urls = {
|
||||
insideUserApi: '/inside/user/',
|
||||
checkPhoneNumber: '/check-phonenumber/',
|
||||
insideCard: '/inside/card/',
|
||||
userSearch: '/user-search/',
|
||||
checkPhoneNumber: '/check-phone-number/',
|
||||
checkCard: '/check-card/',
|
||||
registerCardAndMembership: '/register-card-membership/',
|
||||
renewMembership: '/renew-membership/'
|
||||
};
|
||||
@@ -315,7 +344,8 @@ $(document).ready(function(){
|
||||
registerSubmitButton: $('#register-submit-btn'),
|
||||
usernameField: $('#id_username'),
|
||||
userIdField: $('#id_user_id'),
|
||||
selectedUserWrap: $('.register-card-form--selected-user-wrap'),
|
||||
orderUuidField: $('#id_order_uuid'),
|
||||
selectedEntityWrap: $('.register-card-form--selected-entity-wrap'),
|
||||
toastWrap: $('.toast-wrap'),
|
||||
registerResetButton: $('.register-reset-btn'),
|
||||
searchResetButton: $('.search-reset-btn'),
|
||||
@@ -339,39 +369,48 @@ $(document).ready(function(){
|
||||
/* Card number should exist in the database and not tied to existing user */
|
||||
var val = _dom.cardNumberField.val().trim();
|
||||
var validation_msg = validateCardNumber(val);
|
||||
if( validation_msg !== '' ) {
|
||||
if (validation_msg !== '') {
|
||||
set_field_state(_dom.cardNumberField, 'error', validation_msg);
|
||||
return;
|
||||
}
|
||||
$.getJSON(urls.insideCard, {card_number: val}, function(data) {
|
||||
if(data.error) {
|
||||
$.getJSON(urls.checkCard, {card_number: val}, function(data) {
|
||||
if (data.error) {
|
||||
update_submit_button();
|
||||
cardForm.fields.cardNumber = false;
|
||||
set_field_state(_dom.cardNumberField, 'error', data.error);
|
||||
return;
|
||||
}
|
||||
var card = data.card;
|
||||
var user = data.user;
|
||||
var today_plus_one_month = moment().add(1, 'month');
|
||||
|
||||
if(!card) {
|
||||
var card = data;
|
||||
var user = data.user;
|
||||
var order = data.order;
|
||||
var today_plus_thirty_days = moment().add(30, 'days');
|
||||
|
||||
if (!card) {
|
||||
cardForm.fields.cardNumber = false;
|
||||
set_field_state(_dom.cardNumberField, 'error', 'Cannot find card number in database.');
|
||||
set_field_state(_dom.cardNumberField, 'error',
|
||||
'Cannot find card number in database.');
|
||||
}
|
||||
else if(card && card.registered !== "" && user === null && moment(card.expires) <= today_plus_one_month) {
|
||||
/* An allready registered card (with no user) can repurchase membership if expired */
|
||||
else if (card && card.registered !== null && user === null && order && !order.product.is_valid) {
|
||||
/* An already registered card (with no user) can repurchase membership if expired */
|
||||
set_selected_order(order);
|
||||
cardForm.fields.cardNumber = true;
|
||||
set_field_state(_dom.cardNumberField, 'success', 'Card number is in use (not activated) and belongs to ' + format_phone_number(card.owner_phone_number) + '.');
|
||||
set_field_state(_dom.cardNumberField, 'success',
|
||||
'Card number is in use (not activated) and belongs to ' + format_phone_number(order.phone_number) + '.');
|
||||
}
|
||||
else if(card && card.registered !== "") {
|
||||
var owner_string = 'phone number: '+ format_phone_number(card.owner_phone_number);
|
||||
if(user) {
|
||||
owner_string = 'existing user: ' + user.firstname + ' ' + user.lastname + ' (' + format_phone_number(user.number) + ')';
|
||||
else if (card && card.registered !== null) {
|
||||
var owner_string = '???';
|
||||
if (user) {
|
||||
owner_string = 'existing user: ' + user.first_name + ' ' + user.last_name + ' (' + format_phone_number(user.phone_number) + ')';
|
||||
} else {
|
||||
set_selected_order(order);
|
||||
owner_string = 'phone number: '+ format_phone_number(order.phone_number);
|
||||
}
|
||||
cardForm.fields.cardNumber = false;
|
||||
set_field_state(_dom.cardNumberField, 'error', 'Card number is in use and belongs to '+ owner_string +'.');
|
||||
set_field_state(_dom.cardNumberField, 'error',
|
||||
'Card number is in use and belongs to '+ owner_string +'.');
|
||||
}
|
||||
else if(card && user === null) {
|
||||
else if (card && user === null) {
|
||||
cardForm.fields.cardNumber = true;
|
||||
set_field_state(_dom.cardNumberField, 'success');
|
||||
} else {
|
||||
@@ -379,6 +418,10 @@ $(document).ready(function(){
|
||||
set_field_state(_dom.cardNumberField, '');
|
||||
}
|
||||
update_submit_button();
|
||||
}).fail(function(data) {
|
||||
cardForm.fields.cardNumber = false;
|
||||
set_field_state(_dom.cardNumberField, 'error',
|
||||
'Cannot find card number in database.');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -389,17 +432,21 @@ $(document).ready(function(){
|
||||
_dom.results.html('');
|
||||
return;
|
||||
}
|
||||
$.getJSON(urls.insideUserApi, {q: val}, function(data) {
|
||||
if(data.results && data.results.length > 0) {
|
||||
_dom.results.html(format_results(data.results));
|
||||
if (searching) {
|
||||
searching.abort();
|
||||
}
|
||||
searching = $.getJSON(urls.userSearch, {search: val}, function(data) {
|
||||
if (data.results && data.results.length > 0) {
|
||||
sorted_results = sort_search_results(data.results);
|
||||
_dom.results.html(format_results(sorted_results));
|
||||
users = data.results;
|
||||
}
|
||||
else if(data.error) {
|
||||
else if (data.error) {
|
||||
_dom.results.html(data.error);
|
||||
}
|
||||
else {
|
||||
if(val !== "") {
|
||||
_dom.results.html("Found no existing user with search param: '"+ val +"'");
|
||||
_dom.results.html("Found no user matching: '"+ val +"'");
|
||||
} else {
|
||||
_dom.results.html('');
|
||||
}
|
||||
@@ -420,7 +467,7 @@ $(document).ready(function(){
|
||||
set_selected_user(_.findWhere(users, {id: user_id}));
|
||||
|
||||
/* Update phone number field */
|
||||
if(number === '-') {
|
||||
if (number === '-') {
|
||||
number = '';
|
||||
}
|
||||
_dom.phoneNumberField.val(number).trigger('input');
|
||||
@@ -438,13 +485,13 @@ $(document).ready(function(){
|
||||
/* Register type */
|
||||
// FIXME: get from form
|
||||
// action: 'new_card_membership', 'update_card', 'add_or_renew', 'sms_card_notify'
|
||||
if(selectedUser === null && pendingSMSMembership === null) {
|
||||
if (selectedUser === null && membershipOrder === null) {
|
||||
payload.action = 'new_card_membership';
|
||||
} else if(selectedUser === null && pendingSMSMembership !== null) {
|
||||
} else if (selectedUser === null && membershipOrder !== null) {
|
||||
payload.action = 'sms_card_notify';
|
||||
payload.purchased = pendingSMSMembership.purchase_date;
|
||||
payload.order_uuid = membershipOrder.uuid;
|
||||
} else {
|
||||
if(selectedUser.is_member === '1') {
|
||||
if (selectedUser.is_member) {
|
||||
payload.action = 'update_card';
|
||||
} else {
|
||||
payload.action = 'add_or_renew'; // Note: could also update card number
|
||||
@@ -456,20 +503,17 @@ $(document).ready(function(){
|
||||
dataType: 'json',
|
||||
type: 'post',
|
||||
headers: {'X-CSRFToken': getCookie('csrftoken')}
|
||||
}).success(function(data){
|
||||
var phone_number;
|
||||
}).done(function(data) {
|
||||
var success_message = 'New card registered ' + payload.card_number;
|
||||
if(payload.action === 'add_or_renew') {
|
||||
var full_name = data.user[0].firstname + ' ' + data.user[0].lastname;
|
||||
if (payload.action === 'add_or_renew') {
|
||||
var full_name = selectedUser.first_name + ' ' + selectedUser.last_name;
|
||||
success_message = 'New membership and card number '+ payload.card_number + ' registered to ' + full_name + ' ';
|
||||
}
|
||||
else if(payload.action ==='new_card_membership') {
|
||||
phone_number = data.card.owner_phone_number;
|
||||
success_message = 'New membership and card registered to ' + format_phone_number(phone_number) + '. Activation SMS sent ';
|
||||
else if (payload.action ==='new_card_membership') {
|
||||
success_message = 'New membership and card registered to ' + format_phone_number(payload.phone_number) + '. Activation SMS sent ';
|
||||
}
|
||||
else if(payload.action === 'sms_card_notify') {
|
||||
phone_number = data.card.owner_phone_number;
|
||||
success_message = 'New card registered to ' + format_phone_number(phone_number) + '. Membership already paid by SMS ('+ pendingSMSMembership.purchase_date +'). Activation SMS sent ';
|
||||
else if (payload.action === 'sms_card_notify') {
|
||||
success_message = 'New card registered to ' + format_phone_number(payload.phone_number) + '. Membership already paid '+ membershipOrder.product.start_date +'. Activation SMS sent ';
|
||||
}
|
||||
set_toast(success_message + ' :-)', 'success');
|
||||
resetCardForm(true);
|
||||
@@ -477,8 +521,12 @@ $(document).ready(function(){
|
||||
}).fail(function(data) {
|
||||
console.log("failed", data);
|
||||
var error_text = data.responseText;
|
||||
if(data.responseJSON) {
|
||||
error_text = data.responseJSON.error;
|
||||
if (data.responseJSON) {
|
||||
if (data.responseJSON.non_field_errors) {
|
||||
error_text = data.responseJSON.non_field_errors.join('<br>');
|
||||
} else {
|
||||
error_text = 'Not sure why. :-(';
|
||||
}
|
||||
}
|
||||
set_toast('Failed! '+ error_text, 'error');
|
||||
});
|
||||
@@ -487,35 +535,44 @@ $(document).ready(function(){
|
||||
/* Membership renewal button */
|
||||
_dom.membershipSubmitButton.on('click', function(e) {
|
||||
e.preventDefault();
|
||||
if(!cardForm.fields.phoneNumber || selectedUser.card_number_active === '') {
|
||||
set_toast('Either users phone number is not valid or user does not have a card registered.', 'error');
|
||||
if (!selectedUser && !membershipOrder) {
|
||||
set_toast('Computer says no.', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
var payload = getFormData(_dom.registerCardForm);
|
||||
if( pendingSMSMembership !== null) {
|
||||
payload.purchased = pendingSMSMembership.purchase_date;
|
||||
}
|
||||
else if( selectedUser.expires && moment(selectedUser.expires) > moment() ) {
|
||||
payload.purchased = selectedUser.expires; // future purchase date
|
||||
|
||||
/* If order, make sure to bring along both card number and phone number */
|
||||
if (membershipOrder) {
|
||||
payload.card_number = membershipOrder.member_card;
|
||||
payload.phone_number = membershipOrder.phone_number;
|
||||
}
|
||||
|
||||
$.ajax(urls.renewMembership, {
|
||||
data: JSON.stringify(payload),
|
||||
contentType: 'application/json',
|
||||
dataType: 'json',
|
||||
type: 'post',
|
||||
headers: {'X-CSRFToken': getCookie('csrftoken')}
|
||||
}).success(function(data) {
|
||||
var full_name = data.user[0].firstname + ' ' + data.user[0].lastname;
|
||||
var success_message = 'Membership renewed for ' + full_name + ' ';
|
||||
set_toast(success_message + ' :-)', 'success');
|
||||
}).done(function(data) {
|
||||
var name = 'unknown';
|
||||
if (data.user) {
|
||||
name = selectedUser.first_name + ' ' + selectedUser.last_name;
|
||||
} else {
|
||||
name = 'phone number ' + data.phone_number;
|
||||
}
|
||||
var success_message = 'Membership renewed for ' + name + ' :-)';
|
||||
set_toast(success_message, 'success');
|
||||
resetCardForm(true);
|
||||
|
||||
}).fail(function(data) {
|
||||
console.log("failed", data);
|
||||
var error_text = data.responseText;
|
||||
if(data.responseJSON) {
|
||||
error_text = data.responseJSON.error;
|
||||
if (data.responseJSON) {
|
||||
if (data.responseJSON.non_field_errors) {
|
||||
error_text = data.responseJSON.non_field_errors.join('<br>');
|
||||
} else {
|
||||
error_text = 'Not sure why. :-(';
|
||||
}
|
||||
}
|
||||
set_toast('Failed! '+ error_text, 'error');
|
||||
});
|
||||
@@ -526,6 +583,11 @@ $(document).ready(function(){
|
||||
/* Render selected user in search form */
|
||||
render_selected_user(selectedUser);
|
||||
});
|
||||
/* On order uuid change */
|
||||
_dom.orderUuidField.on('change', function() {
|
||||
/* Render selected order */
|
||||
render_selected_order(membershipOrder);
|
||||
});
|
||||
/* Reset buttons */
|
||||
_dom.registerResetButton.on('click', function() {
|
||||
resetCardForm();
|
||||
@@ -541,7 +603,7 @@ $(document).ready(function(){
|
||||
|
||||
/* Render initial placeholder user */
|
||||
var selected_user_html = nunjucksEnv.render('search_result.html', {placeholder: true});
|
||||
_dom.selectedUserWrap.html(selected_user_html);
|
||||
_dom.selectedEntityWrap.html(selected_user_html);
|
||||
|
||||
/* Initial focus */
|
||||
if(_dom.usernameField) {
|
||||
|
||||
@@ -70,7 +70,7 @@ input[type=number] {
|
||||
.glyphicon-phone-large {
|
||||
font-size: 26px;
|
||||
}
|
||||
.register-card-form--selected-user-wrap {
|
||||
.register-card-form--selected-entity-wrap {
|
||||
min-height: 78px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
@@ -86,6 +86,11 @@ input[type=number] {
|
||||
|
||||
}
|
||||
|
||||
#membership-submit-btn:not(:disabled) {
|
||||
background-color: #dff0d8;
|
||||
border-color: #3c763d;
|
||||
}
|
||||
|
||||
.query-form {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
@@ -111,7 +116,7 @@ input[type=number] {
|
||||
.label-card-yes {
|
||||
color: $green-color;
|
||||
}
|
||||
.label-is-active {
|
||||
.label-is-volunteer {
|
||||
background-color: $active-color;
|
||||
}
|
||||
[type=radio] {
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
{% if not placeholder %}
|
||||
<label for="{{ res.id }}" data-phone-number="{{ res.number }}" data-user-id="{{ res.id }}" class="list-group-item search-result can-register-card{% if res.is_member == "1" %} member{% else %} not-member{% endif %}">
|
||||
<label for="{{ res.id }}" data-phone-number="{{ res.phone_number }}" data-user-id="{{ res.id }}" class="list-group-item search-result can-register-card{% if res.is_member %} member{% else %} not-member{% endif %}">
|
||||
<input type="radio" name="user" id="{{ res.id }}"{% if checked %} checked{% endif %}>
|
||||
<div class="name">
|
||||
<span class="glyphicon glyphicon-user"></span> {{ res.firstname }} {{ res.lastname }}
|
||||
<span class="glyphicon glyphicon-user"></span> {{ res.first_name }} {{ res.last_name }}
|
||||
</div>
|
||||
<!-- Phone number -->
|
||||
<div class="phone-number"><span class="glyphicon glyphicon-phone"></span> {{ res.number|phoneNumber }}</div>
|
||||
<div class="phone-number"><span class="glyphicon glyphicon-phone"></span> {{ res.phone_number|phoneNumber }}</div>
|
||||
<div class="labels">
|
||||
<!-- Membership -->
|
||||
{% if res.is_member == "1" %}
|
||||
<span class="label label-success">Member: {{res.expires|default('Lifelong')}}</span>
|
||||
{% elif res.expires == "0000-00-00" %}
|
||||
{% if res.is_member == true %}
|
||||
<span class="label label-success">Member: {{res.last_membership.end_date or 'Lifelong'}}</span>
|
||||
{% elif res.last_membership == null %}
|
||||
<span class="label label-default">Registered</span>
|
||||
{% else %}
|
||||
<span class="label label-warning">Expired: {{ res.expires }}</span>
|
||||
<span class="label label-warning">Expired: {{ res.last_membership.end_date }}</span>
|
||||
{% endif %}
|
||||
<!-- Card -->
|
||||
{% if res.card_number_active and res.card_is_legacy != '' %}
|
||||
<span class="label label-card label-card-yes"><span class="card-icon"></span> {{ res.card_number_active }}</span>
|
||||
{% if res.active_member_card %}
|
||||
<span class="label label-card label-card-yes"><span class="card-icon"></span> {{ res.active_member_card.card_number }}</span>
|
||||
{% else %}
|
||||
<span class="label label-card label-card-no"><span class="card-icon"></span> No card</span>
|
||||
{% endif %}
|
||||
<!-- Is active -->
|
||||
{% if res.is_active == "1" %}
|
||||
<span class="label label-is-active">Active</span>
|
||||
<!-- Is volunteer -->
|
||||
{% if res.is_volunteer %}
|
||||
<span class="label label-is-volunteer">Volunteer</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if not no_user_actions %}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<div class="list-group-item search-result entity-type-order">
|
||||
<div class="name">
|
||||
<input type="radio" name="user" checked>
|
||||
<span class="glyphicon glyphicon-user"></span> <em>Unregistered member</em>
|
||||
</div>
|
||||
<div class="phone-number"><span class="glyphicon glyphicon-phone"></span> {{ order.phone_number|phoneNumber }}</div>
|
||||
<div class="labels">
|
||||
<!-- Membership -->
|
||||
{% if order.product.is_valid == true %}
|
||||
<span class="label label-success">Member: {{ order.product.end_date or 'Lifelong' }}</span>
|
||||
{% else %}
|
||||
<span class="label label-warning">Expired: {{ order.product.end_date }}</span>
|
||||
{% endif %}
|
||||
<!-- Card -->
|
||||
{% if order.member_card %}
|
||||
<span class="label label-card label-card-yes"><span class="card-icon"></span> {{ order.member_card }}</span>
|
||||
{% else %}
|
||||
<span class="label label-card label-card-no"><span class="card-icon"></span> No card</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
Vendored
+185
-123
@@ -20,20 +20,7 @@ function getParameterByName(name) {
|
||||
results = regex.exec(location.search);
|
||||
return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
|
||||
}
|
||||
function update_user_with_card_details(user) {
|
||||
/* Cards with a number lower than this is legacy as of 2015-08 */
|
||||
var legacy_card_limit = 100000000;
|
||||
|
||||
for(var j=0; j<user.cards.length; j++) {
|
||||
if(parseInt(user.cards[j].card_number, 10) < legacy_card_limit) {
|
||||
user.cards[j].is_legacy = "1";
|
||||
}
|
||||
if(user.cards[j].is_active == "1") {
|
||||
user.card_number_active = user.cards[j].card_number;
|
||||
}
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
function format_phone_number(str) {
|
||||
if(!str || str.length <= 1) {
|
||||
@@ -46,20 +33,36 @@ function format_phone_number(str) {
|
||||
return str;
|
||||
}
|
||||
|
||||
function sort_search_results(results) {
|
||||
return _.sortBy(results, function (x) {
|
||||
if (x.last_membership) {
|
||||
if (x.last_membership.end_date) {
|
||||
return 0 - moment(x.last_membership.end_date).unix();
|
||||
}
|
||||
return 0 - moment(x.last_membership.start_date).unix();
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
function format_results(results) {
|
||||
results = _.map(results, update_user_with_card_details);
|
||||
return nunjucksEnv.render('search_results.html', {'results': results});
|
||||
}
|
||||
function render_selected_user(user_data) {
|
||||
var context;
|
||||
if(user_data === undefined || user_data === null) {
|
||||
if (!user_data) {
|
||||
context = {placeholder: true}; // dummy card
|
||||
} else {
|
||||
user_data = update_user_with_card_details(user_data);
|
||||
context = {res: user_data, checked: true, no_user_actions: true};
|
||||
}
|
||||
var selected_user_html = nunjucksEnv.render('search_result.html', context);
|
||||
_dom.selectedUserWrap.html(selected_user_html);
|
||||
_dom.selectedEntityWrap.html(selected_user_html);
|
||||
}
|
||||
function render_selected_order(order) {
|
||||
if (!order) { return; }
|
||||
var context = {order: order, checked: true, no_user_actions: true};
|
||||
var selected_order_html = nunjucksEnv.render('selected_order.html', context);
|
||||
_dom.selectedEntityWrap.html(selected_order_html);
|
||||
}
|
||||
function set_toast(message, message_type) {
|
||||
var context = {
|
||||
@@ -76,15 +79,9 @@ function set_toast(message, message_type) {
|
||||
}
|
||||
function set_selected_user(user, update_search_result) {
|
||||
selectedUser = user;
|
||||
var new_val = '';
|
||||
updateMemberShipButton(user, null);
|
||||
|
||||
if(user) {
|
||||
new_val = user.id;
|
||||
}
|
||||
|
||||
updateMemberShipButton(user);
|
||||
|
||||
_dom.userIdField.val(new_val).trigger('change');
|
||||
_dom.userIdField.val((user && user.id) || '').trigger('change');
|
||||
if(update_search_result) {
|
||||
var stale_search_result = _dom.results.find('.search-result').removeClass('selected');
|
||||
stale_search_result.find('input').prop('checked', false);
|
||||
@@ -95,6 +92,13 @@ function set_selected_user(user, update_search_result) {
|
||||
}
|
||||
}
|
||||
}
|
||||
function set_selected_order(order) {
|
||||
membershipOrder = order;
|
||||
if (order) {
|
||||
updateMemberShipButton(null, order);
|
||||
}
|
||||
_dom.orderUuidField.val((order && order.uuid) || '').trigger('change');
|
||||
}
|
||||
|
||||
function set_field_state(field_element, state, help_text) {
|
||||
if(!help_text) {
|
||||
@@ -140,12 +144,10 @@ function resetCardForm(reset_native) {
|
||||
set_field_state(_dom.cardNumberField, '');
|
||||
cardForm.fields.cardNumber = false;
|
||||
selectedUser = null;
|
||||
membershipOrder = null;
|
||||
_dom.userIdField.val('').trigger('change');
|
||||
|
||||
_dom.membershipTrialCheckBox.prop('checked', false);
|
||||
|
||||
pendingSMSMembership = null;
|
||||
|
||||
/* Disable submit buttons */
|
||||
_dom.registerSubmitButton.prop('disabled', true);
|
||||
_dom.membershipSubmitButton.prop('disabled', true);
|
||||
@@ -170,16 +172,34 @@ function update_submit_button() {
|
||||
}
|
||||
_dom.registerSubmitButton.prop('disabled', true);
|
||||
}
|
||||
function updateMemberShipButton(user) {
|
||||
var today_plus_one_month = moment().add(1, 'month').format('YYYY-MM-DD');
|
||||
/* Existing member with upcoming expiry and card */
|
||||
if(user && user.is_member === '1' && user.expires <= today_plus_one_month && user.card_number_active !== '') {
|
||||
function updateMemberShipButton(user, order) {
|
||||
var today_plus_thirty_days = moment().add(30, 'days').format('YYYY-MM-DD');
|
||||
/* User with valid membership */
|
||||
if (user && user.is_member) {
|
||||
/* ...which is lifelong cannot renew */
|
||||
if (user.last_membership.membership_type == 'lifelong') {
|
||||
_dom.membershipSubmitButton.prop('disabled', true);
|
||||
}
|
||||
/* ...or expiring soon and the user has a card */
|
||||
//else if (user.last_membership.end_date <= today_plus_thirty_days && user.active_member_card) {
|
||||
/* ...with a membership that expires soon can renew */
|
||||
else if (user.last_membership.end_date <= today_plus_thirty_days) {
|
||||
_dom.membershipSubmitButton.prop('enabled', false);
|
||||
}
|
||||
}
|
||||
/* User with expired membership can renew */
|
||||
// else if (user && !user.is_member && user.active_member_card) {
|
||||
else if (user && !user.is_member) {
|
||||
_dom.membershipSubmitButton.prop('disabled', false);
|
||||
}
|
||||
/* User with card, but expired membership */
|
||||
else if(user && user.is_member !== '1' && user.card_number_active !== '') {
|
||||
_dom.membershipSubmitButton.prop('disabled', false);
|
||||
} else {
|
||||
/* Order */
|
||||
else if (order) {
|
||||
/* If the membership has expired it can be renewed */
|
||||
if (!order.product.is_valid && order.product.end_date <= today_plus_thirty_days) {
|
||||
_dom.membershipSubmitButton.prop('disabled', false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
_dom.membershipSubmitButton.prop('disabled', true);
|
||||
}
|
||||
}
|
||||
@@ -187,7 +207,7 @@ function validatePhoneNumber(val) {
|
||||
if(val.length === 0) {
|
||||
cardForm.fields.phoneNumber = false;
|
||||
update_submit_button();
|
||||
return 'Phonenumber number should not be empty.';
|
||||
return 'Phone number should not be empty.';
|
||||
}
|
||||
cardForm.fields.phoneNumber = true;
|
||||
update_submit_button();
|
||||
@@ -204,11 +224,11 @@ function validateCardNumber(val) {
|
||||
cardForm.fields.cardNumber = false;
|
||||
update_submit_button();
|
||||
return 'Card number should start with 1.';
|
||||
}
|
||||
}
|
||||
if(val.length !== 9) {
|
||||
cardForm.fields.cardNumber = false;
|
||||
update_submit_button();
|
||||
return 'Card number should be 9 digits long';
|
||||
return 'Card number should be 9 digits long.';
|
||||
}
|
||||
cardForm.fields.cardNumber = true;
|
||||
update_submit_button();
|
||||
@@ -218,8 +238,10 @@ function validateCardNumber(val) {
|
||||
function getFormData(formElement) {
|
||||
var formData = formElement.serializeArray();
|
||||
formData = _.object(_.map(formData, function (x) {
|
||||
return [x.name, x.value];
|
||||
return [x.name, x.value || null];
|
||||
}));
|
||||
/* no need for radio button state */
|
||||
delete formData.user;
|
||||
|
||||
return formData;
|
||||
}
|
||||
@@ -231,44 +253,50 @@ function checkPhoneNumber() {
|
||||
/* Invalid phone number?*/
|
||||
if(data.error) {
|
||||
set_selected_user(null, true);
|
||||
set_selected_order(null);
|
||||
set_field_state(_dom.phoneNumberField, 'error', data.error);
|
||||
cardForm.fields.phoneNumber = false;
|
||||
pendingSMSMembership = null;
|
||||
update_submit_button();
|
||||
return;
|
||||
}
|
||||
/* Already has valid card membership? */
|
||||
if(data.inside.card && data.inside.card.has_valid_membership == "1") {
|
||||
var card = data.inside.card;
|
||||
var msg = 'Phone number is already tied to card '+ card.card_number + ' and is valid until '+ card.expires +'.';
|
||||
set_field_state(_dom.phoneNumberField, 'error', msg);
|
||||
|
||||
var user = data.user;
|
||||
var order = data.order;
|
||||
var message = '';
|
||||
|
||||
/* Has valid card membership */
|
||||
if (!user && order && order.member_card && order.product.is_valid) {
|
||||
message = 'Phone number is already tied to card '+ order.member_card + ' and is valid until '+ order.product.end_date +'.';
|
||||
set_field_state(_dom.phoneNumberField, 'error', message);
|
||||
cardForm.fields.phoneNumber = false;
|
||||
pendingSMSMembership = null;
|
||||
set_selected_order(order);
|
||||
update_submit_button();
|
||||
return;
|
||||
}
|
||||
|
||||
var inside = data.inside;
|
||||
var tekstmelding = data.tekstmelding;
|
||||
var _user = null;
|
||||
var _success_msg = '';
|
||||
|
||||
if(inside.users.length == 1) {
|
||||
if (user) {
|
||||
/* Existing user */
|
||||
_user = inside.users[0];
|
||||
_success_msg = 'Phone number belongs to existing user.';
|
||||
pendingSMSMembership = null;
|
||||
} else if(tekstmelding.result !== null) {
|
||||
/* Pending SMS membership (not activated yet) */
|
||||
_success_msg = 'Phone number has valid membership (paid via SMS). OK to give out card.';
|
||||
pendingSMSMembership = tekstmelding.result;
|
||||
message = 'Phone number belongs to existing user.';
|
||||
set_field_state(_dom.phoneNumberField, 'success', message);
|
||||
set_selected_user(user, true);
|
||||
set_selected_order(null);
|
||||
cardForm.fields.phoneNumber = true;
|
||||
update_submit_button();
|
||||
} else if (order) {
|
||||
set_selected_order(order);
|
||||
/* Valid membership, no card associated */
|
||||
if (order.product.is_valid) {
|
||||
message = 'Phone number has a valid membership.';
|
||||
} else {
|
||||
message = 'Phone number has an expired membership.';
|
||||
}
|
||||
} else {
|
||||
/* Valid phone number with no existing user, card membership or pending SMS membership */
|
||||
pendingSMSMembership = null;
|
||||
/* Valid phone number associated user or order */
|
||||
set_selected_order(null);
|
||||
set_selected_user(null);
|
||||
}
|
||||
|
||||
set_field_state(_dom.phoneNumberField, 'success', _success_msg);
|
||||
set_selected_user(_user, true);
|
||||
set_field_state(_dom.phoneNumberField, 'success', message);
|
||||
cardForm.fields.phoneNumber = true;
|
||||
update_submit_button();
|
||||
});
|
||||
@@ -277,8 +305,9 @@ function checkPhoneNumber() {
|
||||
/* Init and global vars */
|
||||
var _dom;
|
||||
var users;
|
||||
var searching; /* search ajax request */
|
||||
var selectedUser;
|
||||
var pendingSMSMembership;
|
||||
var membershipOrder; /* selected order object */
|
||||
var cardForm = {
|
||||
fields: {
|
||||
cardNumber: false,
|
||||
@@ -295,9 +324,9 @@ var nunjucksEnv = new nunjucks.Environment();
|
||||
nunjucksEnv.addFilter('phoneNumber', format_phone_number);
|
||||
|
||||
var urls = {
|
||||
insideUserApi: '/inside/user/',
|
||||
checkPhoneNumber: '/check-phonenumber/',
|
||||
insideCard: '/inside/card/',
|
||||
userSearch: '/user-search/',
|
||||
checkPhoneNumber: '/check-phone-number/',
|
||||
checkCard: '/check-card/',
|
||||
registerCardAndMembership: '/register-card-membership/',
|
||||
renewMembership: '/renew-membership/'
|
||||
};
|
||||
@@ -315,7 +344,8 @@ $(document).ready(function(){
|
||||
registerSubmitButton: $('#register-submit-btn'),
|
||||
usernameField: $('#id_username'),
|
||||
userIdField: $('#id_user_id'),
|
||||
selectedUserWrap: $('.register-card-form--selected-user-wrap'),
|
||||
orderUuidField: $('#id_order_uuid'),
|
||||
selectedEntityWrap: $('.register-card-form--selected-entity-wrap'),
|
||||
toastWrap: $('.toast-wrap'),
|
||||
registerResetButton: $('.register-reset-btn'),
|
||||
searchResetButton: $('.search-reset-btn'),
|
||||
@@ -339,39 +369,48 @@ $(document).ready(function(){
|
||||
/* Card number should exist in the database and not tied to existing user */
|
||||
var val = _dom.cardNumberField.val().trim();
|
||||
var validation_msg = validateCardNumber(val);
|
||||
if( validation_msg !== '' ) {
|
||||
if (validation_msg !== '') {
|
||||
set_field_state(_dom.cardNumberField, 'error', validation_msg);
|
||||
return;
|
||||
}
|
||||
$.getJSON(urls.insideCard, {card_number: val}, function(data) {
|
||||
if(data.error) {
|
||||
$.getJSON(urls.checkCard, {card_number: val}, function(data) {
|
||||
if (data.error) {
|
||||
update_submit_button();
|
||||
cardForm.fields.cardNumber = false;
|
||||
set_field_state(_dom.cardNumberField, 'error', data.error);
|
||||
return;
|
||||
}
|
||||
var card = data.card;
|
||||
var user = data.user;
|
||||
var today_plus_one_month = moment().add(1, 'month');
|
||||
|
||||
if(!card) {
|
||||
var card = data;
|
||||
var user = data.user;
|
||||
var order = data.order;
|
||||
var today_plus_thirty_days = moment().add(30, 'days');
|
||||
|
||||
if (!card) {
|
||||
cardForm.fields.cardNumber = false;
|
||||
set_field_state(_dom.cardNumberField, 'error', 'Cannot find card number in database.');
|
||||
set_field_state(_dom.cardNumberField, 'error',
|
||||
'Cannot find card number in database.');
|
||||
}
|
||||
else if(card && card.registered !== "" && user === null && moment(card.expires) <= today_plus_one_month) {
|
||||
/* An allready registered card (with no user) can repurchase membership if expired */
|
||||
else if (card && card.registered !== null && user === null && order && !order.product.is_valid) {
|
||||
/* An already registered card (with no user) can repurchase membership if expired */
|
||||
set_selected_order(order);
|
||||
cardForm.fields.cardNumber = true;
|
||||
set_field_state(_dom.cardNumberField, 'success', 'Card number is in use (not activated) and belongs to ' + format_phone_number(card.owner_phone_number) + '.');
|
||||
set_field_state(_dom.cardNumberField, 'success',
|
||||
'Card number is in use (not activated) and belongs to ' + format_phone_number(order.phone_number) + '.');
|
||||
}
|
||||
else if(card && card.registered !== "") {
|
||||
var owner_string = 'phone number: '+ format_phone_number(card.owner_phone_number);
|
||||
if(user) {
|
||||
owner_string = 'existing user: ' + user.firstname + ' ' + user.lastname + ' (' + format_phone_number(user.number) + ')';
|
||||
else if (card && card.registered !== null) {
|
||||
var owner_string = '???';
|
||||
if (user) {
|
||||
owner_string = 'existing user: ' + user.first_name + ' ' + user.last_name + ' (' + format_phone_number(user.phone_number) + ')';
|
||||
} else {
|
||||
set_selected_order(order);
|
||||
owner_string = 'phone number: '+ format_phone_number(order.phone_number);
|
||||
}
|
||||
cardForm.fields.cardNumber = false;
|
||||
set_field_state(_dom.cardNumberField, 'error', 'Card number is in use and belongs to '+ owner_string +'.');
|
||||
set_field_state(_dom.cardNumberField, 'error',
|
||||
'Card number is in use and belongs to '+ owner_string +'.');
|
||||
}
|
||||
else if(card && user === null) {
|
||||
else if (card && user === null) {
|
||||
cardForm.fields.cardNumber = true;
|
||||
set_field_state(_dom.cardNumberField, 'success');
|
||||
} else {
|
||||
@@ -379,6 +418,10 @@ $(document).ready(function(){
|
||||
set_field_state(_dom.cardNumberField, '');
|
||||
}
|
||||
update_submit_button();
|
||||
}).fail(function(data) {
|
||||
cardForm.fields.cardNumber = false;
|
||||
set_field_state(_dom.cardNumberField, 'error',
|
||||
'Cannot find card number in database.');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -389,17 +432,21 @@ $(document).ready(function(){
|
||||
_dom.results.html('');
|
||||
return;
|
||||
}
|
||||
$.getJSON(urls.insideUserApi, {q: val}, function(data) {
|
||||
if(data.results && data.results.length > 0) {
|
||||
_dom.results.html(format_results(data.results));
|
||||
if (searching) {
|
||||
searching.abort();
|
||||
}
|
||||
searching = $.getJSON(urls.userSearch, {search: val}, function(data) {
|
||||
if (data.results && data.results.length > 0) {
|
||||
sorted_results = sort_search_results(data.results);
|
||||
_dom.results.html(format_results(sorted_results));
|
||||
users = data.results;
|
||||
}
|
||||
else if(data.error) {
|
||||
else if (data.error) {
|
||||
_dom.results.html(data.error);
|
||||
}
|
||||
else {
|
||||
if(val !== "") {
|
||||
_dom.results.html("Found no existing user with search param: '"+ val +"'");
|
||||
_dom.results.html("Found no user matching: '"+ val +"'");
|
||||
} else {
|
||||
_dom.results.html('');
|
||||
}
|
||||
@@ -420,7 +467,7 @@ $(document).ready(function(){
|
||||
set_selected_user(_.findWhere(users, {id: user_id}));
|
||||
|
||||
/* Update phone number field */
|
||||
if(number === '-') {
|
||||
if (number === '-') {
|
||||
number = '';
|
||||
}
|
||||
_dom.phoneNumberField.val(number).trigger('input');
|
||||
@@ -438,13 +485,13 @@ $(document).ready(function(){
|
||||
/* Register type */
|
||||
// FIXME: get from form
|
||||
// action: 'new_card_membership', 'update_card', 'add_or_renew', 'sms_card_notify'
|
||||
if(selectedUser === null && pendingSMSMembership === null) {
|
||||
if (selectedUser === null && membershipOrder === null) {
|
||||
payload.action = 'new_card_membership';
|
||||
} else if(selectedUser === null && pendingSMSMembership !== null) {
|
||||
} else if (selectedUser === null && membershipOrder !== null) {
|
||||
payload.action = 'sms_card_notify';
|
||||
payload.purchased = pendingSMSMembership.purchase_date;
|
||||
payload.order_uuid = membershipOrder.uuid;
|
||||
} else {
|
||||
if(selectedUser.is_member === '1') {
|
||||
if (selectedUser.is_member) {
|
||||
payload.action = 'update_card';
|
||||
} else {
|
||||
payload.action = 'add_or_renew'; // Note: could also update card number
|
||||
@@ -456,20 +503,17 @@ $(document).ready(function(){
|
||||
dataType: 'json',
|
||||
type: 'post',
|
||||
headers: {'X-CSRFToken': getCookie('csrftoken')}
|
||||
}).success(function(data){
|
||||
var phone_number;
|
||||
}).done(function(data) {
|
||||
var success_message = 'New card registered ' + payload.card_number;
|
||||
if(payload.action === 'add_or_renew') {
|
||||
var full_name = data.user[0].firstname + ' ' + data.user[0].lastname;
|
||||
if (payload.action === 'add_or_renew') {
|
||||
var full_name = selectedUser.first_name + ' ' + selectedUser.last_name;
|
||||
success_message = 'New membership and card number '+ payload.card_number + ' registered to ' + full_name + ' ';
|
||||
}
|
||||
else if(payload.action ==='new_card_membership') {
|
||||
phone_number = data.card.owner_phone_number;
|
||||
success_message = 'New membership and card registered to ' + format_phone_number(phone_number) + '. Activation SMS sent ';
|
||||
else if (payload.action ==='new_card_membership') {
|
||||
success_message = 'New membership and card registered to ' + format_phone_number(payload.phone_number) + '. Activation SMS sent ';
|
||||
}
|
||||
else if(payload.action === 'sms_card_notify') {
|
||||
phone_number = data.card.owner_phone_number;
|
||||
success_message = 'New card registered to ' + format_phone_number(phone_number) + '. Membership already paid by SMS ('+ pendingSMSMembership.purchase_date +'). Activation SMS sent ';
|
||||
else if (payload.action === 'sms_card_notify') {
|
||||
success_message = 'New card registered to ' + format_phone_number(payload.phone_number) + '. Membership already paid '+ membershipOrder.product.start_date +'. Activation SMS sent ';
|
||||
}
|
||||
set_toast(success_message + ' :-)', 'success');
|
||||
resetCardForm(true);
|
||||
@@ -477,8 +521,12 @@ $(document).ready(function(){
|
||||
}).fail(function(data) {
|
||||
console.log("failed", data);
|
||||
var error_text = data.responseText;
|
||||
if(data.responseJSON) {
|
||||
error_text = data.responseJSON.error;
|
||||
if (data.responseJSON) {
|
||||
if (data.responseJSON.non_field_errors) {
|
||||
error_text = data.responseJSON.non_field_errors.join('<br>');
|
||||
} else {
|
||||
error_text = 'Not sure why. :-(';
|
||||
}
|
||||
}
|
||||
set_toast('Failed! '+ error_text, 'error');
|
||||
});
|
||||
@@ -487,35 +535,44 @@ $(document).ready(function(){
|
||||
/* Membership renewal button */
|
||||
_dom.membershipSubmitButton.on('click', function(e) {
|
||||
e.preventDefault();
|
||||
if(!cardForm.fields.phoneNumber || selectedUser.card_number_active === '') {
|
||||
set_toast('Either users phone number is not valid or user does not have a card registered.', 'error');
|
||||
if (!selectedUser && !membershipOrder) {
|
||||
set_toast('Computer says no.', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
var payload = getFormData(_dom.registerCardForm);
|
||||
if( pendingSMSMembership !== null) {
|
||||
payload.purchased = pendingSMSMembership.purchase_date;
|
||||
}
|
||||
else if( selectedUser.expires && moment(selectedUser.expires) > moment() ) {
|
||||
payload.purchased = selectedUser.expires; // future purchase date
|
||||
|
||||
/* If order, make sure to bring along both card number and phone number */
|
||||
if (membershipOrder) {
|
||||
payload.card_number = membershipOrder.member_card;
|
||||
payload.phone_number = membershipOrder.phone_number;
|
||||
}
|
||||
|
||||
$.ajax(urls.renewMembership, {
|
||||
data: JSON.stringify(payload),
|
||||
contentType: 'application/json',
|
||||
dataType: 'json',
|
||||
type: 'post',
|
||||
headers: {'X-CSRFToken': getCookie('csrftoken')}
|
||||
}).success(function(data) {
|
||||
var full_name = data.user[0].firstname + ' ' + data.user[0].lastname;
|
||||
var success_message = 'Membership renewed for ' + full_name + ' ';
|
||||
set_toast(success_message + ' :-)', 'success');
|
||||
}).done(function(data) {
|
||||
var name = 'unknown';
|
||||
if (data.user) {
|
||||
name = selectedUser.first_name + ' ' + selectedUser.last_name;
|
||||
} else {
|
||||
name = 'phone number ' + data.phone_number;
|
||||
}
|
||||
var success_message = 'Membership renewed for ' + name + ' :-)';
|
||||
set_toast(success_message, 'success');
|
||||
resetCardForm(true);
|
||||
|
||||
}).fail(function(data) {
|
||||
console.log("failed", data);
|
||||
var error_text = data.responseText;
|
||||
if(data.responseJSON) {
|
||||
error_text = data.responseJSON.error;
|
||||
if (data.responseJSON) {
|
||||
if (data.responseJSON.non_field_errors) {
|
||||
error_text = data.responseJSON.non_field_errors.join('<br>');
|
||||
} else {
|
||||
error_text = 'Not sure why. :-(';
|
||||
}
|
||||
}
|
||||
set_toast('Failed! '+ error_text, 'error');
|
||||
});
|
||||
@@ -526,6 +583,11 @@ $(document).ready(function(){
|
||||
/* Render selected user in search form */
|
||||
render_selected_user(selectedUser);
|
||||
});
|
||||
/* On order uuid change */
|
||||
_dom.orderUuidField.on('change', function() {
|
||||
/* Render selected order */
|
||||
render_selected_order(membershipOrder);
|
||||
});
|
||||
/* Reset buttons */
|
||||
_dom.registerResetButton.on('click', function() {
|
||||
resetCardForm();
|
||||
@@ -541,7 +603,7 @@ $(document).ready(function(){
|
||||
|
||||
/* Render initial placeholder user */
|
||||
var selected_user_html = nunjucksEnv.render('search_result.html', {placeholder: true});
|
||||
_dom.selectedUserWrap.html(selected_user_html);
|
||||
_dom.selectedEntityWrap.html(selected_user_html);
|
||||
|
||||
/* Initial focus */
|
||||
if(_dom.usernameField) {
|
||||
|
||||
Vendored
+112
-26
@@ -1,17 +1,19 @@
|
||||
(function() {(window.nunjucksPrecompiled = window.nunjucksPrecompiled || {})["search_result.html"] = (function() {function root(env, context, frame, runtime, cb) {
|
||||
(function() {(window.nunjucksPrecompiled = window.nunjucksPrecompiled || {})["search_result.html"] = (function() {
|
||||
function root(env, context, frame, runtime, cb) {
|
||||
var lineno = null;
|
||||
var colno = null;
|
||||
var output = "";
|
||||
try {
|
||||
var parentTemplate = null;
|
||||
if(!runtime.contextOrFrameLookup(context, frame, "placeholder")) {
|
||||
output += "\n <label for=\"";
|
||||
output += runtime.suppressValue(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"id", env.opts.autoescape), env.opts.autoescape);
|
||||
output += runtime.suppressValue(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"id"), env.opts.autoescape);
|
||||
output += "\" data-phone-number=\"";
|
||||
output += runtime.suppressValue(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"number", env.opts.autoescape), env.opts.autoescape);
|
||||
output += runtime.suppressValue(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"phone_number"), env.opts.autoescape);
|
||||
output += "\" data-user-id=\"";
|
||||
output += runtime.suppressValue(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"id", env.opts.autoescape), env.opts.autoescape);
|
||||
output += runtime.suppressValue(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"id"), env.opts.autoescape);
|
||||
output += "\" class=\"list-group-item search-result can-register-card";
|
||||
if(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"is_member", env.opts.autoescape) == "1") {
|
||||
if(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"is_member")) {
|
||||
output += " member";
|
||||
;
|
||||
}
|
||||
@@ -20,42 +22,42 @@ output += " not-member";
|
||||
;
|
||||
}
|
||||
output += "\">\n <input type=\"radio\" name=\"user\" id=\"";
|
||||
output += runtime.suppressValue(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"id", env.opts.autoescape), env.opts.autoescape);
|
||||
output += runtime.suppressValue(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"id"), env.opts.autoescape);
|
||||
output += "\"";
|
||||
if(runtime.contextOrFrameLookup(context, frame, "checked")) {
|
||||
output += " checked";
|
||||
;
|
||||
}
|
||||
output += ">\n <div class=\"name\">\n <span class=\"glyphicon glyphicon-user\"></span> ";
|
||||
output += runtime.suppressValue(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"firstname", env.opts.autoescape), env.opts.autoescape);
|
||||
output += runtime.suppressValue(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"first_name"), env.opts.autoescape);
|
||||
output += " ";
|
||||
output += runtime.suppressValue(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"lastname", env.opts.autoescape), env.opts.autoescape);
|
||||
output += runtime.suppressValue(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"last_name"), env.opts.autoescape);
|
||||
output += "\n </div>\n <!-- Phone number -->\n <div class=\"phone-number\"><span class=\"glyphicon glyphicon-phone\"></span> ";
|
||||
output += runtime.suppressValue(env.getFilter("phoneNumber").call(context, runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"number", env.opts.autoescape)), env.opts.autoescape);
|
||||
output += runtime.suppressValue(env.getFilter("phoneNumber").call(context, runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"phone_number")), env.opts.autoescape);
|
||||
output += "</div>\n <div class=\"labels\">\n <!-- Membership -->\n ";
|
||||
if(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"is_member", env.opts.autoescape) == "1") {
|
||||
if(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"is_member") == true) {
|
||||
output += "\n <span class=\"label label-success\">Member: ";
|
||||
output += runtime.suppressValue(env.getFilter("default").call(context, runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"expires", env.opts.autoescape),"Lifelong"), env.opts.autoescape);
|
||||
output += runtime.suppressValue(runtime.memberLookup((runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"last_membership")),"end_date") || "Lifelong", env.opts.autoescape);
|
||||
output += "</span>\n ";
|
||||
;
|
||||
}
|
||||
else {
|
||||
if(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"expires", env.opts.autoescape) == "0000-00-00") {
|
||||
if(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"last_membership") == runtime.contextOrFrameLookup(context, frame, "null")) {
|
||||
output += "\n <span class=\"label label-default\">Registered</span>\n ";
|
||||
;
|
||||
}
|
||||
else {
|
||||
output += "\n <span class=\"label label-warning\">Expired: ";
|
||||
output += runtime.suppressValue(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"expires", env.opts.autoescape), env.opts.autoescape);
|
||||
output += runtime.suppressValue(runtime.memberLookup((runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"last_membership")),"end_date"), env.opts.autoescape);
|
||||
output += "</span>\n ";
|
||||
;
|
||||
}
|
||||
;
|
||||
}
|
||||
output += "\n <!-- Card -->\n ";
|
||||
if(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"card_number_active", env.opts.autoescape) && runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"card_is_legacy", env.opts.autoescape) != "") {
|
||||
if(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"active_member_card")) {
|
||||
output += "\n <span class=\"label label-card label-card-yes\"><span class=\"card-icon\"></span> ";
|
||||
output += runtime.suppressValue(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"card_number_active", env.opts.autoescape), env.opts.autoescape);
|
||||
output += runtime.suppressValue(runtime.memberLookup((runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"active_member_card")),"card_number"), env.opts.autoescape);
|
||||
output += "</span>\n ";
|
||||
;
|
||||
}
|
||||
@@ -63,20 +65,20 @@ else {
|
||||
output += "\n <span class=\"label label-card label-card-no\"><span class=\"card-icon\"></span> No card</span>\n ";
|
||||
;
|
||||
}
|
||||
output += "\n <!-- Is active -->\n ";
|
||||
if(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"is_active", env.opts.autoescape) == "1") {
|
||||
output += "\n <span class=\"label label-is-active\">Active</span>\n ";
|
||||
output += "\n <!-- Is volunteer -->\n ";
|
||||
if(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"is_volunteer")) {
|
||||
output += "\n <span class=\"label label-is-volunteer\">Volunteer</span>\n ";
|
||||
;
|
||||
}
|
||||
output += "\n </div>\n ";
|
||||
if(!runtime.contextOrFrameLookup(context, frame, "no_user_actions")) {
|
||||
output += "\n <div class=\"user-actions\">\n <div class=\"btn-group\">\n <!--<a href=\"#\" class=\"btn btn-default";
|
||||
if(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"is_member", env.opts.autoescape) == "1") {
|
||||
if(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"is_member") == "1") {
|
||||
output += " disabled";
|
||||
;
|
||||
}
|
||||
output += "\">Membership</a>\n <a href=\"#\" class=\"btn btn-default\">Reg. card</a>-->\n <div class=\"btn-group\" role=\"group\">\n <button type=\"button\" class=\"btn btn-default dropdown-toggle\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">\n <span class=\"glyphicon glyphicon-option-vertical\"></span>\n </button>\n <ul class=\"dropdown-menu\">\n <li><a href=\"https://inside.studentersamfundet.no/index.php?page=display-user&userid=";
|
||||
output += runtime.suppressValue(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"id", env.opts.autoescape), env.opts.autoescape);
|
||||
output += runtime.suppressValue(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "res")),"id"), env.opts.autoescape);
|
||||
output += "\" target=\"_blank\">Edit in Inside</a></li>\n </ul>\n </div>\n </div>\n </div>\n ";
|
||||
;
|
||||
}
|
||||
@@ -89,7 +91,11 @@ output += runtime.suppressValue(env.getFilter("phoneNumber").call(context, runti
|
||||
output += "</div>\n <div class=\"labels\">\n <span class=\"label label-card\"><span class=\"card-icon\"></span> New card</span>\n </div>\n </div>\n";
|
||||
;
|
||||
}
|
||||
if(parentTemplate) {
|
||||
parentTemplate.rootRenderFunc(env, context, frame, runtime, cb);
|
||||
} else {
|
||||
cb(null, output);
|
||||
}
|
||||
;
|
||||
} catch (e) {
|
||||
cb(runtime.handleError(e, lineno, colno));
|
||||
@@ -98,14 +104,17 @@ cb(null, output);
|
||||
return {
|
||||
root: root
|
||||
};
|
||||
|
||||
})();
|
||||
})();
|
||||
|
||||
(function() {(window.nunjucksPrecompiled = window.nunjucksPrecompiled || {})["search_results.html"] = (function() {function root(env, context, frame, runtime, cb) {
|
||||
(function() {(window.nunjucksPrecompiled = window.nunjucksPrecompiled || {})["search_results.html"] = (function() {
|
||||
function root(env, context, frame, runtime, cb) {
|
||||
var lineno = null;
|
||||
var colno = null;
|
||||
var output = "";
|
||||
try {
|
||||
var parentTemplate = null;
|
||||
output += "<div class=\"list-group\">\n ";
|
||||
frame = frame.push();
|
||||
var t_3 = runtime.contextOrFrameLookup(context, frame, "results");
|
||||
@@ -121,18 +130,36 @@ frame.set("loop.first", t_1 === 0);
|
||||
frame.set("loop.last", t_1 === t_2 - 1);
|
||||
frame.set("loop.length", t_2);
|
||||
output += "\n ";
|
||||
env.getTemplate("search_result.html", false, "search_results.html", function(t_7,t_5) {
|
||||
var tasks = [];
|
||||
tasks.push(
|
||||
function(callback) {
|
||||
env.getTemplate("search_result.html", false, "search_results.html", null, function(t_7,t_5) {
|
||||
if(t_7) { cb(t_7); return; }
|
||||
t_5.render(context.getVariables(), frame.push(), function(t_8,t_6) {
|
||||
callback(null,t_5);});
|
||||
});
|
||||
tasks.push(
|
||||
function(template, callback){
|
||||
template.render(context.getVariables(), frame, function(t_8,t_6) {
|
||||
if(t_8) { cb(t_8); return; }
|
||||
output += t_6
|
||||
callback(null,t_6);});
|
||||
});
|
||||
tasks.push(
|
||||
function(result, callback){
|
||||
output += result;
|
||||
callback(null);
|
||||
});
|
||||
env.waterfall(tasks, function(){
|
||||
output += "\n ";
|
||||
})});
|
||||
});
|
||||
}
|
||||
}
|
||||
frame = frame.pop();
|
||||
output += "\n</div>";
|
||||
if(parentTemplate) {
|
||||
parentTemplate.rootRenderFunc(env, context, frame, runtime, cb);
|
||||
} else {
|
||||
cb(null, output);
|
||||
}
|
||||
;
|
||||
} catch (e) {
|
||||
cb(runtime.handleError(e, lineno, colno));
|
||||
@@ -141,14 +168,68 @@ cb(null, output);
|
||||
return {
|
||||
root: root
|
||||
};
|
||||
|
||||
})();
|
||||
})();
|
||||
|
||||
(function() {(window.nunjucksPrecompiled = window.nunjucksPrecompiled || {})["toast.html"] = (function() {function root(env, context, frame, runtime, cb) {
|
||||
(function() {(window.nunjucksPrecompiled = window.nunjucksPrecompiled || {})["selected_order.html"] = (function() {
|
||||
function root(env, context, frame, runtime, cb) {
|
||||
var lineno = null;
|
||||
var colno = null;
|
||||
var output = "";
|
||||
try {
|
||||
var parentTemplate = null;
|
||||
output += "<div class=\"list-group-item search-result entity-type-order\">\n <div class=\"name\">\n <input type=\"radio\" name=\"user\" checked>\n <span class=\"glyphicon glyphicon-user\"></span> <em>Unregistered member</em>\n </div>\n <div class=\"phone-number\"><span class=\"glyphicon glyphicon-phone\"></span> ";
|
||||
output += runtime.suppressValue(env.getFilter("phoneNumber").call(context, runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "order")),"phone_number")), env.opts.autoescape);
|
||||
output += "</div>\n <div class=\"labels\">\n <!-- Membership -->\n ";
|
||||
if(runtime.memberLookup((runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "order")),"product")),"is_valid") == true) {
|
||||
output += "\n <span class=\"label label-success\">Member: ";
|
||||
output += runtime.suppressValue(runtime.memberLookup((runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "order")),"product")),"end_date") || "Lifelong", env.opts.autoescape);
|
||||
output += "</span>\n ";
|
||||
;
|
||||
}
|
||||
else {
|
||||
output += "\n <span class=\"label label-warning\">Expired: ";
|
||||
output += runtime.suppressValue(runtime.memberLookup((runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "order")),"product")),"end_date"), env.opts.autoescape);
|
||||
output += "</span>\n ";
|
||||
;
|
||||
}
|
||||
output += "\n <!-- Card -->\n ";
|
||||
if(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "order")),"member_card")) {
|
||||
output += "\n <span class=\"label label-card label-card-yes\"><span class=\"card-icon\"></span> ";
|
||||
output += runtime.suppressValue(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "order")),"member_card"), env.opts.autoescape);
|
||||
output += "</span>\n ";
|
||||
;
|
||||
}
|
||||
else {
|
||||
output += "\n <span class=\"label label-card label-card-no\"><span class=\"card-icon\"></span> No card</span>\n ";
|
||||
;
|
||||
}
|
||||
output += "\n </div>\n</div>\n";
|
||||
if(parentTemplate) {
|
||||
parentTemplate.rootRenderFunc(env, context, frame, runtime, cb);
|
||||
} else {
|
||||
cb(null, output);
|
||||
}
|
||||
;
|
||||
} catch (e) {
|
||||
cb(runtime.handleError(e, lineno, colno));
|
||||
}
|
||||
}
|
||||
return {
|
||||
root: root
|
||||
};
|
||||
|
||||
})();
|
||||
})();
|
||||
|
||||
(function() {(window.nunjucksPrecompiled = window.nunjucksPrecompiled || {})["toast.html"] = (function() {
|
||||
function root(env, context, frame, runtime, cb) {
|
||||
var lineno = null;
|
||||
var colno = null;
|
||||
var output = "";
|
||||
try {
|
||||
var parentTemplate = null;
|
||||
output += "<span class=\"toast-";
|
||||
output += runtime.suppressValue(runtime.contextOrFrameLookup(context, frame, "message_type"), env.opts.autoescape);
|
||||
output += "\"><span class=\"glyphicon glyphicon-";
|
||||
@@ -156,7 +237,11 @@ output += runtime.suppressValue(runtime.contextOrFrameLookup(context, frame, "ic
|
||||
output += "\"></span> ";
|
||||
output += runtime.suppressValue(runtime.contextOrFrameLookup(context, frame, "message"), env.opts.autoescape);
|
||||
output += "</span>";
|
||||
if(parentTemplate) {
|
||||
parentTemplate.rootRenderFunc(env, context, frame, runtime, cb);
|
||||
} else {
|
||||
cb(null, output);
|
||||
}
|
||||
;
|
||||
} catch (e) {
|
||||
cb(runtime.handleError(e, lineno, colno));
|
||||
@@ -165,5 +250,6 @@ cb(null, output);
|
||||
return {
|
||||
root: root
|
||||
};
|
||||
|
||||
})();
|
||||
})();
|
||||
Vendored
+9524
-6916
File diff suppressed because it is too large.
Load diff
Vendored
+10
-1
@@ -1 +1,10 @@
|
||||
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0}mark{background:#ff0;color:#000}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}hr{box-sizing:content-box;height:0}pre{overflow:auto}samp{font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}@media print{*,*:before,*:after{background:transparent!important;color:#000!important;box-shadow:none!important;text-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href)")"}abbr[title]:after{content:" (" attr(title)")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url("../fonts/glyphicons-halflings-regular.eot");src:url("../fonts/glyphicons-halflings-regular.eot?#iefix") format("embedded-opentype"),url("../fonts/glyphicons-halflings-regular.woff2") format("woff2"),url("../fonts/glyphicons-halflings-regular.woff") format("woff"),url("../fonts/glyphicons-halflings-regular.ttf") format("truetype"),url("../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular") format("svg")}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before,.glyphicon-eur:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.gLine truncated
|
||||
@charset "UTF-8";
|
||||
/*!
|
||||
* Bootstrap v3.3.7 (http://getbootstrap.com)
|
||||
* Copyright 2011-2016 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
*/
|
||||
/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
|
||||
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}legend,td,th{padding:0}
|
||||
/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */
|
||||
@media print{*,:after,:before{background:0 0!important;color:#000!important;box-shadow:none!important;text-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{border:1px solid #999}thead{display:table-header-group}blockquote,img,pre,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format("embedded-opentype"),url(../fonts/glyphicons-halflings-regular.woff2) format("woff2"),url(../fonts/glyphicons-halflings-regular.woff) format("woff"),url(../fonts/glyphicons-halflings-regular.ttf) format("truetype"),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format("svg")}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\Line truncated
|
||||
+1
-1
@@ -116,7 +116,7 @@ gulp.task('serve', ['styles'], function () {
|
||||
|
||||
gulp.task('watch', ['serve'], function () {
|
||||
browserSync.init({
|
||||
proxy: 'localhost:8000'
|
||||
proxy: 'localhost:8001'
|
||||
});
|
||||
|
||||
// watch for changes
|
||||
|
||||
+4449
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user