Adds renew membership only button

This commit is contained in:
nikolark committed 2015-08-16 23:39:10 +02:00
1 parent 47303857ea
commit afb2d6705e
8 files changed
+3463 -148

No files matched your search

+1 -1
View File
@@ -11,6 +11,6 @@ class SearchUserForm(forms.Form):
class AddCardForm(forms.Form):
card_number = forms.IntegerField(widget=forms.NumberInput())
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)
+6 -10
View File
@@ -6,15 +6,7 @@
<form class="register-card-form" autocomplete="off">
{% csrf_token %}
<h3>{% trans "Card and membership" %}</h3>
<p>Enter card and phone number to register a new membership or add card to an existing user.
<!--
Add no-user membership [DONE].
Add membership for new user and existing user [DONE].
Renew membership for existing user [DONE].
Register card to existing user [DONE].
Replace card for existing user [DONE]
-->
</p>
<p>Enter card and phone number to register a new membership or add card to an existing user.</p>
{{ add_card_form|bootstrap }}
<div class="register-card-form--selected-user-section">
<label>{% trans "Member" %}</label>
@@ -25,7 +17,11 @@
<li>Registering a card number with a phone number already tied to an existing user, will add the card to that user.</li>
</ul>
<button id="register-submit-btn" type="submit" class="btn btn-primary btn-lg" disabled>{% trans "Register card" %}</button>
<button type="reset" class="register-reset-btn btn btn-default">{% trans "Reset" %}</button>
<button type="reset" class="register-reset-btn btn btn-default">{% trans "Reset" %}</button><br><br>
<ul>
<li>If an existing user is found, you can renew the membership only (up to 30 days before expiry).</li>
</ul>
<button id="membership-submit-btn" type="submit" class="btn btn-default" disabled>{% trans "Renew membership only" %}</button>
</form>
</div>
<div class="col-sm-7 section-search">
+2 -1
View File
@@ -1,6 +1,6 @@
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
register_card_and_membership, stats_card_sales, renew_membership
urlpatterns = [
url(r'^$', register, name='register'),
@@ -8,5 +8,6 @@ urlpatterns = [
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'^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')
]
+12
View File
@@ -149,6 +149,18 @@ def register_card_and_membership(request):
return JsonResponse(response.json(), status=response.status_code)
@login_required()
def renew_membership(request):
if request.method != 'POST':
return JsonResponse({'error': 'Only method POST supported'})
post_data = json.loads(request.body)
response = inside_update_membership(post_data.get('user_id'), purchased=post_data.get('purchased'))
return JsonResponse(response.json(), status=response.status_code)
def stats_card_sales(request):
sale_events = [KassaEvent.ADD_OR_RENEW, KassaEvent.NEW_CARD_MEMBERSHIP]
+122 -67
View File
@@ -77,9 +77,13 @@ function set_toast(message, message_type) {
function set_selected_user(user, update_search_result) {
selectedUser = user;
var new_val = '';
if(user) {
new_val = user.id;
}
updateMemberShipButton(user);
_dom.userIdField.val(new_val).trigger('change');
if(update_search_result) {
var stale_search_result = _dom.results.find('.search-result').removeClass('selected');
@@ -140,8 +144,9 @@ function resetCardForm(reset_native) {
pendingSMSMembership = null;
/* Disable submit button */
/* Disable submit buttons */
_dom.registerSubmitButton.prop('disabled', true);
_dom.membershipSubmitButton.prop('disabled', true);
}
function resetSearchForm(reset_native) {
if(reset_native) {
@@ -163,6 +168,19 @@ function update_submit_button() {
}
_dom.registerSubmitButton.prop('disabled', true);
}
function updateMemberShipButton(user) {
var today_plus_one_month = moment().subtract(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 !== '') {
_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 {
_dom.membershipSubmitButton.prop('disabled', true);
}
}
function validatePhoneNumber(val) {
if(val.length === 0) {
cardForm.fields.phoneNumber = false;
@@ -204,6 +222,56 @@ function getFormData(formElement) {
return formData;
}
/* Phone number as you type */
function checkPhoneNumber() {
var val = _dom.phoneNumberField.val().trim();
$.getJSON(urls.checkPhoneNumber, {phone_number: val}, function(data) {
/* Invalid phone number?*/
if(data.error) {
set_selected_user(null, true);
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) {
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);
cardForm.fields.phoneNumber = false;
pendingSMSMembership = null;
update_submit_button();
return;
}
var inside = data.inside;
var tekstmelding = data.tekstmelding;
var _user = null;
var _success_msg = '';
if(inside.users.length == 1) {
/* 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;
} else {
/* Valid phone number with no existing user, card membership or pending SMS membership */
pendingSMSMembership = null;
}
set_field_state(_dom.phoneNumberField, 'success', _success_msg);
set_selected_user(_user, true);
cardForm.fields.phoneNumber = true;
update_submit_button();
});
}
/* Init and global vars */
var _dom;
var users;
@@ -221,6 +289,16 @@ var state_to_icon = {
error: 'remove'
};
var nunjucksEnv = new nunjucks.Environment();
/* Add filter |phoneNumber */
nunjucksEnv.addFilter('phoneNumber', format_phone_number);
var urls = {
insideUserApi: '/inside/user/',
checkPhoneNumber: '/check-phonenumber/',
insideCard: '/inside/card/',
registerCardAndMembership: '/register-card-membership/',
renewMembership: '/renew-membership/'
};
@@ -238,66 +316,9 @@ $(document).ready(function(){
selectedUserWrap: $('.register-card-form--selected-user-wrap'),
toastWrap: $('.toast-wrap'),
registerResetButton: $('.register-reset-btn'),
searchResetButton: $('.search-reset-btn')
searchResetButton: $('.search-reset-btn'),
membershipSubmitButton: $('#membership-submit-btn')
};
var urls = {
insideUserApi: '/inside/user/',
checkPhoneNumber: '/check-phonenumber/',
insideCard: '/inside/card/',
registerCardAndMembership: '/register-card-membership/'
};
/* Add filter |phoneNumber */
nunjucksEnv.addFilter('phoneNumber', format_phone_number);
/* Phone number as you type */
function checkPhoneNumber() {
var val = _dom.phoneNumberField.val().trim();
$.getJSON(urls.checkPhoneNumber, {phone_number: val}, function(data) {
/* Invalid phone number?*/
if(data.error) {
set_selected_user(null, true);
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) {
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);
cardForm.fields.phoneNumber = false;
pendingSMSMembership = null;
update_submit_button();
return;
}
var inside = data.inside;
var tekstmelding = data.tekstmelding;
var _user = null;
var _success_msg = '';
if(inside.users.length == 1) {
/* 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;
} else {
/* Valid phone number with no existing user, card membership or pending SMS membership */
pendingSMSMembership = null;
}
set_field_state(_dom.phoneNumberField, 'success', _success_msg);
set_selected_user(_user, true);
cardForm.fields.phoneNumber = true;
update_submit_button();
});
}
var lazyCheckPhoneNumber = _.debounce(checkPhoneNumber, 250);
_dom.phoneNumberField.on('input', function() {
@@ -395,7 +416,7 @@ $(document).ready(function(){
}
_dom.phoneNumberField.val(number).trigger('input');
});
/* On submit button click */
_dom.registerSubmitButton.on('click', function(e) {
e.preventDefault();
@@ -412,6 +433,7 @@ $(document).ready(function(){
payload.action = 'new_card_membership';
} else if(selectedUser === null && pendingSMSMembership !== null) {
payload.action = 'sms_card_notify';
payload.purchased = pendingSMSMembership.purchase_date;
} else {
if(selectedUser.is_member === '1') {
payload.action = 'update_card';
@@ -454,6 +476,43 @@ $(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');
return;
}
var payload = getFormData(_dom.registerCardForm);
if( pendingSMSMembership !== null) {
payload.purchased = pendingSMSMembership.purchase_date;
} else {
payload.purchased = selectedUser.expires; // future purchase date
}
console.log(payload);
$.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');
resetCardForm(true);
}).fail(function(data) {
console.log("failed", data);
var error_text = data.responseText;
if(data.responseJSON) {
error_text = data.responseJSON.error;
}
set_toast('Failed! '+ error_text, 'error');
});
});
/* On user id change */
_dom.userIdField.on('change', function() {
/* Render selected user in search form */
@@ -480,19 +539,15 @@ $(document).ready(function(){
if(_dom.usernameField) {
_dom.usernameField.focus();
}
if(_dom.phoneNumberField) {
_dom.phoneNumberField.focus();
}
/* Load query params */
/* FIXME: does not trigger validation and selected user preview */
if( getParameterByName('user_id') ) {
_dom.userIdField.val(getParameterByName('user_id')).trigger('change');
}
if( getParameterByName('phone_number') ) {
_dom.phoneNumberField.val(getParameterByName('phone_number'));
_dom.phoneNumberField.val(getParameterByName('phone_number')).trigger('input');
}
if( getParameterByName('card_number') ) {
_dom.cardNumberField.val(getParameterByName('card_number'));
_dom.cardNumberField.val(getParameterByName('card_number')).trigger('input');
}
});
+2 -1
View File
@@ -6,7 +6,8 @@
"underscore": "1.8.3",
"list.js": "1.1.1",
"bootstrap-sass": "3.3.5",
"nunjucks": "~1.3.4"
"nunjucks": "~1.3.4",
"moment": "~2.10.6"
},
"devDependencies": {},
"resolutions": {
+122 -67
View File
@@ -77,9 +77,13 @@ function set_toast(message, message_type) {
function set_selected_user(user, update_search_result) {
selectedUser = user;
var new_val = '';
if(user) {
new_val = user.id;
}
updateMemberShipButton(user);
_dom.userIdField.val(new_val).trigger('change');
if(update_search_result) {
var stale_search_result = _dom.results.find('.search-result').removeClass('selected');
@@ -140,8 +144,9 @@ function resetCardForm(reset_native) {
pendingSMSMembership = null;
/* Disable submit button */
/* Disable submit buttons */
_dom.registerSubmitButton.prop('disabled', true);
_dom.membershipSubmitButton.prop('disabled', true);
}
function resetSearchForm(reset_native) {
if(reset_native) {
@@ -163,6 +168,19 @@ function update_submit_button() {
}
_dom.registerSubmitButton.prop('disabled', true);
}
function updateMemberShipButton(user) {
var today_plus_one_month = moment().subtract(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 !== '') {
_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 {
_dom.membershipSubmitButton.prop('disabled', true);
}
}
function validatePhoneNumber(val) {
if(val.length === 0) {
cardForm.fields.phoneNumber = false;
@@ -204,6 +222,56 @@ function getFormData(formElement) {
return formData;
}
/* Phone number as you type */
function checkPhoneNumber() {
var val = _dom.phoneNumberField.val().trim();
$.getJSON(urls.checkPhoneNumber, {phone_number: val}, function(data) {
/* Invalid phone number?*/
if(data.error) {
set_selected_user(null, true);
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) {
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);
cardForm.fields.phoneNumber = false;
pendingSMSMembership = null;
update_submit_button();
return;
}
var inside = data.inside;
var tekstmelding = data.tekstmelding;
var _user = null;
var _success_msg = '';
if(inside.users.length == 1) {
/* 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;
} else {
/* Valid phone number with no existing user, card membership or pending SMS membership */
pendingSMSMembership = null;
}
set_field_state(_dom.phoneNumberField, 'success', _success_msg);
set_selected_user(_user, true);
cardForm.fields.phoneNumber = true;
update_submit_button();
});
}
/* Init and global vars */
var _dom;
var users;
@@ -221,6 +289,16 @@ var state_to_icon = {
error: 'remove'
};
var nunjucksEnv = new nunjucks.Environment();
/* Add filter |phoneNumber */
nunjucksEnv.addFilter('phoneNumber', format_phone_number);
var urls = {
insideUserApi: '/inside/user/',
checkPhoneNumber: '/check-phonenumber/',
insideCard: '/inside/card/',
registerCardAndMembership: '/register-card-membership/',
renewMembership: '/renew-membership/'
};
@@ -238,66 +316,9 @@ $(document).ready(function(){
selectedUserWrap: $('.register-card-form--selected-user-wrap'),
toastWrap: $('.toast-wrap'),
registerResetButton: $('.register-reset-btn'),
searchResetButton: $('.search-reset-btn')
searchResetButton: $('.search-reset-btn'),
membershipSubmitButton: $('#membership-submit-btn')
};
var urls = {
insideUserApi: '/inside/user/',
checkPhoneNumber: '/check-phonenumber/',
insideCard: '/inside/card/',
registerCardAndMembership: '/register-card-membership/'
};
/* Add filter |phoneNumber */
nunjucksEnv.addFilter('phoneNumber', format_phone_number);
/* Phone number as you type */
function checkPhoneNumber() {
var val = _dom.phoneNumberField.val().trim();
$.getJSON(urls.checkPhoneNumber, {phone_number: val}, function(data) {
/* Invalid phone number?*/
if(data.error) {
set_selected_user(null, true);
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) {
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);
cardForm.fields.phoneNumber = false;
pendingSMSMembership = null;
update_submit_button();
return;
}
var inside = data.inside;
var tekstmelding = data.tekstmelding;
var _user = null;
var _success_msg = '';
if(inside.users.length == 1) {
/* 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;
} else {
/* Valid phone number with no existing user, card membership or pending SMS membership */
pendingSMSMembership = null;
}
set_field_state(_dom.phoneNumberField, 'success', _success_msg);
set_selected_user(_user, true);
cardForm.fields.phoneNumber = true;
update_submit_button();
});
}
var lazyCheckPhoneNumber = _.debounce(checkPhoneNumber, 250);
_dom.phoneNumberField.on('input', function() {
@@ -395,7 +416,7 @@ $(document).ready(function(){
}
_dom.phoneNumberField.val(number).trigger('input');
});
/* On submit button click */
_dom.registerSubmitButton.on('click', function(e) {
e.preventDefault();
@@ -412,6 +433,7 @@ $(document).ready(function(){
payload.action = 'new_card_membership';
} else if(selectedUser === null && pendingSMSMembership !== null) {
payload.action = 'sms_card_notify';
payload.purchased = pendingSMSMembership.purchase_date;
} else {
if(selectedUser.is_member === '1') {
payload.action = 'update_card';
@@ -454,6 +476,43 @@ $(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');
return;
}
var payload = getFormData(_dom.registerCardForm);
if( pendingSMSMembership !== null) {
payload.purchased = pendingSMSMembership.purchase_date;
} else {
payload.purchased = selectedUser.expires; // future purchase date
}
console.log(payload);
$.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');
resetCardForm(true);
}).fail(function(data) {
console.log("failed", data);
var error_text = data.responseText;
if(data.responseJSON) {
error_text = data.responseJSON.error;
}
set_toast('Failed! '+ error_text, 'error');
});
});
/* On user id change */
_dom.userIdField.on('change', function() {
/* Render selected user in search form */
@@ -480,19 +539,15 @@ $(document).ready(function(){
if(_dom.usernameField) {
_dom.usernameField.focus();
}
if(_dom.phoneNumberField) {
_dom.phoneNumberField.focus();
}
/* Load query params */
/* FIXME: does not trigger validation and selected user preview */
if( getParameterByName('user_id') ) {
_dom.userIdField.val(getParameterByName('user_id')).trigger('change');
}
if( getParameterByName('phone_number') ) {
_dom.phoneNumberField.val(getParameterByName('phone_number'));
_dom.phoneNumberField.val(getParameterByName('phone_number')).trigger('input');
}
if( getParameterByName('card_number') ) {
_dom.cardNumberField.val(getParameterByName('card_number'));
_dom.cardNumberField.val(getParameterByName('card_number')).trigger('input');
}
});
+3196 -1
View File
File diff suppressed because it is too large. Load diff