diff --git a/README.md b/README.md index 9d23e4e..33d226f 100644 --- a/README.md +++ b/README.md @@ -13,16 +13,16 @@ Kassa helps you register purchased membership cards and memberships. It's a tool python manage.py migrate ## 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 +Create a user in Galtinn with the following permissions: +* galtinn | User | Can view User +* galtinn | Member card | Can change Member card +* galtinn | Member card | Can view Member card +* galtinn | Membership | Can add Membership +* galtinn | Membership | Can view Membership +* galtinn | 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/ +Fetch GALTINN_API_KEY: + curl -H "Content-Type: application/json" -X POST -d '{"username":"apiuser","password":"test"}' GALTINN_API_URL/auth/obtain-token/ If developing you can disable calls to Tekstmelding in local_settings.py: TEKSTMELDING_ENABLED = False diff --git a/apps/kassa/admin.py b/apps/kassa/admin.py index 1ad497c..040a78a 100644 --- a/apps/kassa/admin.py +++ b/apps/kassa/admin.py @@ -3,10 +3,10 @@ from django.contrib import admin class KassaEventAdmin(admin.ModelAdmin): - list_display = ['id', 'event', 'card_number', 'user_phone_number', 'user_dusken_id', + list_display = ['id', 'event', 'card_number', 'user_phone_number', 'user_galtinn_id', 'user_inside_id', 'created', 'transaction_id'] list_filter = ['event'] - search_fields = ['card_number', 'user_phone_number', 'user_dusken_id', + search_fields = ['card_number', 'user_phone_number', 'user_galtinn_id', 'user_inside_id', 'transaction_id'] admin.site.register(KassaEvent, KassaEventAdmin) diff --git a/apps/kassa/migrations/0008_kassaevent_user_dusken_id.py b/apps/kassa/migrations/0008_kassaevent_user_galtinn_id.py similarity index 92% rename from apps/kassa/migrations/0008_kassaevent_user_dusken_id.py rename to apps/kassa/migrations/0008_kassaevent_user_galtinn_id.py index 87801c8..639cc66 100644 --- a/apps/kassa/migrations/0008_kassaevent_user_dusken_id.py +++ b/apps/kassa/migrations/0008_kassaevent_user_galtinn_id.py @@ -14,7 +14,7 @@ class Migration(migrations.Migration): operations = [ migrations.AddField( model_name='kassaevent', - name='user_dusken_id', + name='user_galtinn_id', field=models.IntegerField(blank=True, null=True), ), ] diff --git a/apps/kassa/models.py b/apps/kassa/models.py index 571a0e2..96d0b83 100644 --- a/apps/kassa/models.py +++ b/apps/kassa/models.py @@ -21,7 +21,7 @@ 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_galtinn_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) diff --git a/apps/kassa/urls.py b/apps/kassa/urls.py index b49b9dc..4e8c178 100644 --- a/apps/kassa/urls.py +++ b/apps/kassa/urls.py @@ -1,7 +1,6 @@ from django.conf.urls import url -from apps.kassa.views import (register, user_search, check_card, - 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, renew_membership) urlpatterns = [ url(r'^$', register, name='register'), @@ -10,5 +9,4 @@ urlpatterns = [ 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') ] diff --git a/apps/kassa/utils.py b/apps/kassa/utils.py index 689076b..dcf6871 100644 --- a/apps/kassa/utils.py +++ b/apps/kassa/utils.py @@ -7,68 +7,67 @@ import logging logger = logging.getLogger(__name__) -dusken_auth = { - 'Authorization': 'Token {}'.format(settings.DUSKEN_API_KEY) +galtinn_auth = { + 'Authorization': 'Token {}'.format(settings.GALTINN_API_KEY) +} + +tekstmelding_auth = { + 'Authorization': 'Token {}'.format(settings.TEKSTMELDING_API_KEY) } -def tekstmelding_new_membership_card(card_number, phone_number): +def send_sms_activation_link(phone_number, transaction_id): + to = phone_number.replace('+', ''), + code = transaction_id[:8] + activation_url = settings.GALTINN_ACTIVATION_URL.format(to=to, code=code) + message = settings.TEKSTMELDING_ACTIVATION_SMS_TEMPLATE.format(url=activation_url) payload = { - 'phone_number': phone_number, - 'card_number': card_number, - 'action': 'new_card_no_user', + 'to': to, + 'message': message } - if not settings.TEKSTMELDING_ENABLED: - logger.info('Tekstmelding disabled. Payload would be: ', payload) + logger.info('Tekstmelding disabled. Payload would be: {}'.format(payload)) return - - url = '{}kassa/new-membership-card'.format(settings.TEKSTMELDING_API_URL) - response = requests.post( - url, - json=payload, - params={'api_key': settings.TEKSTMELDING_API_KEY}, - headers={'Content-Type': 'application/json'} - ) - + url = '{}send'.format(settings.TEKSTMELDING_API_URL) + response = requests.post(url, json=payload, headers=tekstmelding_auth) return response.json() def get_card(card_number): - url = '{}cards/{}/'.format(settings.DUSKEN_API_URL, card_number) - return requests.get(url, headers=dusken_auth) + url = '{}cards/{}/'.format(settings.GALTINN_API_URL, card_number) + return requests.get(url, headers=galtinn_auth) def get_order(order_uuid): - url = '{}orders/{}/'.format(settings.DUSKEN_API_URL, order_uuid) - return requests.get(url, headers=dusken_auth) + url = '{}orders/{}/'.format(settings.GALTINN_API_URL, order_uuid) + return requests.get(url, headers=galtinn_auth) def get_latest_order_by_card(card_number): - url = '{}orders/'.format(settings.DUSKEN_API_URL) + url = '{}orders/'.format(settings.GALTINN_API_URL) payload = {'card_number': card_number} - orders = requests.get(url, params=payload, headers=dusken_auth).json() + orders = requests.get(url, params=payload, headers=galtinn_auth).json() return orders.get('results')[0] def get_latest_order_by_phone(phone_number): - url = '{}orders/'.format(settings.DUSKEN_API_URL) + url = '{}orders/'.format(settings.GALTINN_API_URL) payload = {'phone_number': phone_number} - orders = requests.get(url, params=payload, headers=dusken_auth).json() + orders = requests.get(url, params=payload, headers=galtinn_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) + url = '{}users/{}/'.format(settings.GALTINN_API_URL, user_id) + return requests.get(url, headers=galtinn_auth) def get_user_by_phone(phone_number): - url = '{}users/'.format(settings.DUSKEN_API_URL) + url = '{}users/'.format(settings.GALTINN_API_URL) payload = {'phone_number': phone_number} - users = requests.get(url, params=payload, headers=dusken_auth).json() + users = requests.get(url, params=payload, headers=galtinn_auth).json() if users.get('count') == 1: return users.get('results')[0] return None @@ -76,19 +75,19 @@ def get_user_by_phone(phone_number): 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) + url = '{}kassa/card/'.format(settings.GALTINN_API_URL) payload = { 'member_card': card_number, 'user': user_id, 'order': order_uuid, } - return requests.patch(url, json=payload, headers=dusken_auth) + return requests.patch(url, json=payload, headers=galtinn_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) + url = '{}kassa/membership/'.format(settings.GALTINN_API_URL) payload = { 'user': user, 'phone_number': phone_number, @@ -96,7 +95,7 @@ def update_membership(user=None, phone_number=None, card_number=None, membership 'membership_type': membership_type, 'transaction_id': transaction_id, } - return requests.post(url, json=payload, headers=dusken_auth) + return requests.post(url, json=payload, headers=galtinn_auth) def format_phone_number(number): diff --git a/apps/kassa/views.py b/apps/kassa/views.py index 3729440..c5aa32c 100644 --- a/apps/kassa/views.py +++ b/apps/kassa/views.py @@ -13,9 +13,9 @@ import requests from apps.kassa.models import KassaEvent from apps.kassa.forms import AddCardForm, SearchUserForm -from apps.kassa.utils import tekstmelding_new_membership_card, update_card, get_card, \ +from apps.kassa.utils import send_sms_activation_link, 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 + galtinn_auth, update_membership, format_phone_number, is_autumn logger = logging.getLogger(__name__) @@ -35,8 +35,8 @@ def user_search(request): payload = { 'search': request.GET.get('search', '') } - url = '{}users/'.format(settings.DUSKEN_API_URL) - data = requests.get(url, params=payload, headers=dusken_auth).json() + url = '{}users/'.format(settings.GALTINN_API_URL) + data = requests.get(url, params=payload, headers=galtinn_auth).json() return JsonResponse(data) @@ -100,6 +100,9 @@ def register_card_and_membership(request): phone_number = post_data.get('phone_number') membership_trial = post_data.get('membership_trial') membership_type = 'trial' if membership_trial else 'standard' + transaction_id = uuid.uuid4() + + logger.debug('register_card_and_membership post_data %r', post_data) # Update card number on user or order if action in ('update_card', 'sms_card_notify'): @@ -116,14 +119,14 @@ def register_card_and_membership(request): 'event': KassaEvent.UPDATE_CARD, 'user_phone_number': phone_number, 'card_number': card_number, - 'user_dusken_id': user_id, + 'user_galtinn_id': user_id, + 'transaction_id': transaction_id } logger.debug(event_data) KassaEvent.objects.create(**event_data) # 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, @@ -132,7 +135,7 @@ def register_card_and_membership(request): 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, + user_galtinn_id=user_id, card_number=card_number, user_phone_number=phone_number, transaction_id=transaction_id @@ -145,12 +148,13 @@ def register_card_and_membership(request): event = KassaEvent.SMS_CARD_NOTIFY # FIXME: could be async - tekstmelding_new_membership_card(card_number=card_number, - phone_number=phone_number) + send_sms_activation_link(phone_number=phone_number, + transaction_id=str(transaction_id)) KassaEvent.objects.create( event=event, card_number=card_number, - user_phone_number=phone_number + user_phone_number=phone_number, + transaction_id=transaction_id ) return JsonResponse(response.json(), status=response.status_code) @@ -169,6 +173,8 @@ def renew_membership(request): membership_type = 'trial' if membership_trial else 'standard' transaction_id = str(uuid.uuid4()) + logger.debug('renew_membership post_data %r', post_data) + response = update_membership( user=user_id, phone_number=phone_number, @@ -177,32 +183,8 @@ def renew_membership(request): transaction_id=transaction_id) KassaEvent.objects.create( event=KassaEvent.RENEW_ONLY if membership_trial is None else KassaEvent.MEMBERSHIP_TRIAL, - user_dusken_id=user_id, + user_galtinn_id=user_id, transaction_id=transaction_id ) return JsonResponse(response.json(), status=response.status_code) - - -def stats_card_sales(request): - sale_events = [KassaEvent.ADD_OR_RENEW, KassaEvent.NEW_CARD_MEMBERSHIP, KassaEvent.RENEW_ONLY] - start = request.GET.get('start') - if start: - try: - start_date = timezone.datetime.strptime(start, '%Y-%m-%d') - except ValueError: - logger.info('Invalid start date in param start: \'%s\'', start) - return JsonResponse({'error': 'Invalid start date in param start: \'{}\''.format(start)}) - else: - start_date = timezone.datetime(year=2015, month=8, day=1) - - if not timezone.is_aware(start_date): - start_date = timezone.make_aware(start_date, timezone.get_current_timezone()) - - events = KassaEvent.objects.filter(event__in=sale_events, created__gte=start_date).values_list('created') - grouped = [] - date_format = '%Y-%m-%d' - for key, values in groupby(events, key=lambda row: row[0].strftime(date_format)): - grouped.append({'date': key, 'sales': len(list(values))}) - - return JsonResponse({'memberships': grouped}) diff --git a/kassasite/settings.py b/kassasite/settings.py index 6a21e5c..3f00483 100644 --- a/kassasite/settings.py +++ b/kassasite/settings.py @@ -113,12 +113,14 @@ STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') LOGIN_REDIRECT_URL = '/' -DUSKEN_API_KEY = '' -DUSKEN_API_URL = 'https://dusken.neuf.no/api/' +GALTINN_API_KEY = '' +GALTINN_API_URL = 'https://galtinn.neuf.no/api/' +GALTINN_ACTIVATION_URL = 'https://galtinn.neuf.no/activate/{to}/{code}' TEKSTMELDING_API_KEY = '' TEKSTMELDING_API_URL = 'https://tekstmelding.neuf.no/' TEKSTMELDING_ENABLED = True +TEKSTMELDING_ACTIVATION_SMS_TEMPLATE = 'Velkommen som medlem! Registrer deg her: {url}' CORS_ORIGIN_ALLOW_ALL = True