mirror of
https://github.com/ae-utbm/sith.git
synced 2026-10-16 23:49:20 +00:00
Merge branch 'skia/counter_rework' into 'master'
counter: make click page dynamic to avoid repetitive loading See merge request ae/Sith!278
This commit is contained in:
commit
cb3307509d
10 files changed
+198
-74
No files matched your search
+9
-6
@@ -79,9 +79,11 @@ class ComTest(TestCase):
|
||||
)
|
||||
r = self.client.get(reverse("core:index"))
|
||||
self.assertTrue(r.status_code == 200)
|
||||
self.assertTrue(
|
||||
"""<div id="alert_box">\\n <div class="markdown"><h3>ALERTE!</h3>\\n<p><strong>Caaaataaaapuuuulte!!!!</strong></p>"""
|
||||
in str(r.content)
|
||||
self.assertContains(
|
||||
r,
|
||||
"""<div id="alert_box">
|
||||
<div class="markdown"><h3>ALERTE!</h3>
|
||||
<p><strong>Caaaataaaapuuuulte!!!!</strong></p>""",
|
||||
)
|
||||
|
||||
def test_info_msg(self):
|
||||
@@ -95,9 +97,10 @@ class ComTest(TestCase):
|
||||
)
|
||||
r = self.client.get(reverse("core:index"))
|
||||
self.assertTrue(r.status_code == 200)
|
||||
self.assertTrue(
|
||||
"""<div id="info_box">\\n <div class="markdown"><h3>INFO: <strong>Caaaataaaapuuuulte!!!!</strong></h3>"""
|
||||
in str(r.content)
|
||||
self.assertContains(
|
||||
r,
|
||||
"""<div id="info_box">
|
||||
<div class="markdown"><h3>INFO: <strong>Caaaataaaapuuuulte!!!!</strong></h3>""",
|
||||
)
|
||||
|
||||
def test_birthday_non_subscribed_user(self):
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
var Vue=function(e){"use strict";function t(e,t){const n=Object.create(null),o=e.split(",");for(let r=0;r<o.length;r++)n[o[r]]=!0;return t?e=>!!n[e.toLowerCase()]:e=>!!n[e]}const n=t("Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt"),o=t("itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly");function r(e){return!!e||""===e}function s(e){if(N(e)){const t={};for(let n=0;n<e.length;n++){const o=e[n],r=A(o)?c(o):s(o);if(r)for(const e in r)t[e]=r[e]}return t}return A(e)||M(e)?e:void 0}const i=/;(?![^(]*\))/g,l=/:(.+)/;function c(e){const t={};return e.split(i).forEach((e=>{if(e){const n=e.split(l);n.length>1&&(t[n[0].trim()]=n[1].trim())}})),t}function a(e){let t="";if(A(e))t=e;else if(N(e))for(let n=0;n<e.length;n++){const o=a(e[n]);o&&(t+=o+" ")}else if(M(e))for(const n in e)e[n]&&(t+=n+" ");return t.trim()}const u=t("html,body,base,head,link,meta,style,title,address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,nav,section,div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,ruby,s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,output,progress,select,textarea,details,dialog,menu,summary,template,blockquote,iframe,tfoot"),p=t("svg,animate,animateMotion,animateTransform,circle,clipPath,color-profile,defs,desc,discard,ellipse,feBlend,feColorMatrix,feComponentTransfer,feComposite,feConvolveMatrix,feDiffuseLighting,feDisplacementMap,feDistanceLight,feDropShadow,feFlood,feFuncA,feFuncB,feFuncG,feFuncR,feGaussianBlur,feImage,feMerge,feMergeNode,feMorphology,feOffset,fePointLight,feSpecularLighting,feSpotLight,feTile,feTurbulence,filter,foreignObject,g,hatch,hatchpath,image,line,linearGradient,marker,mask,mesh,meshgradient,meshpatch,meshrow,metadata,mpath,path,pattern,polygon,polyline,radialGradient,rect,set,solidcolor,stop,switch,symbol,text,textPath,title,tspan,unknown,use,view"),f=t("area,base,br,col,embed,hr,img,input,link,meta,param,source,track,wbr");function d(e,t){if(e===t)return!0;let n=R(e),o=R(t);if(n||o)return!(!n||!o)&&e.getTime()===t.getTime();if(n=N(e),o=N(t),n||o)return!(!n||!o)&&function(e,t){if(e.length!==t.length)return!1;let n=!0;for(let o=0;n&&o<e.length;o++)n=d(e[o],t[o]);return n}(e,t);if(n=M(e),o=M(t),n||o){if(!n||!o)return!1;if(Object.keys(e).length!==Object.keys(t).length)return!1;for(const n in e){const o=e.hasOwnProperty(n),r=t.hasOwnProperty(n);if(o&&!r||!o&&r||!d(e[n],t[n]))return!1}}return String(e)===String(t)}function h(e,t){return e.findIndex((e=>d(e,t)))}const m=(e,t)=>t&&t.__v_isRef?m(e,t.value):E(t)?{[`Map(${t.size})`]:[...t.entries()].reduce(((e,[t,n])=>(e[`${t} =>`]=n,e)),{})}:$(t)?{[`Set(${t.size})`]:[...t.values()]}:!M(t)||N(t)||B(t)?t:String(t),g={},v=[],y=()=>{},b=()=>!1,_=/^on[^a-z]/,S=e=>_.test(e),x=e=>e.startsWith("onUpdate:"),C=Object.assign,w=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},k=Object.prototype.hasOwnProperty,T=(e,t)=>k.call(e,t),N=Array.isArray,E=e=>"[object Map]"===I(e),$=e=>"[object Set]"===I(e),R=e=>e instanceof Date,O=e=>"function"==typeof e,A=e=>"string"==typeof e,F=e=>"symbol"==typeof e,M=e=>null!==e&&"object"==typeof e,P=e=>M(e)&&O(e.then)&&O(e.catch),V=Object.prototype.toString,I=e=>V.call(e),B=e=>"[object Object]"===I(e),L=e=>A(e)&&"NaN"!==e&&"-"!==e[0]&&""+parseInt(e,10)===e,j=t(",key,ref,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),U=e=>{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))},H=/-(\w)/g,D=U((e=>e.replace(H,((e,t)=>t?t.toUpperCase():"")))),W=/\B([A-Z])/g,z=U((e=>e.replace(W,"-$1").toLowerCase())),K=U((e=>e.charAt(0).toUpperCase()+e.slice(1))),G=U((e=>e?`on${K(e)}`:"")),q=(e,t)=>!Object.is(e,t),J=(e,t)=>{for(let n=0;n<e.length;n++)e[n](t)},Z=(e,t,n)=>{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value:n})},Y=e=>{const t=parseFloat(e);return isNaN(t)?e:t};let Q;let X;const ee=[];class te{constructor(e=!1){this.active=!0,this.effects=[],this.cleanups=[],!e&&X&&(this.parent=X,this.index=(X.scopes||(X.scopes=[])).push(this)-1)}run(e){if(this.active)try{return this.on(),e()}finally{this.off()}}on(){this.active&&(ee.push(this),X=this)}off(){this.active&&(ee.pop(),X=ee[ee.length-1])}stop(e){if(this.active){if(this.effects.forEach((e=>e.stop())),this.cleanups.forEach((e=>e())),this.scopes&&this.scopes.forEach((e=>e.stop(!0))),this.parent&&!e){const e=this.parent.scopes.pop();e&&e!==this&&(this.parent.scopes[this.index]=e,e.index=this.index)}this.active=!1}}}function ne(e,t){(t=t||X)&&t.active&&t.effects.push(e)}const oe=e=>{const t=new Set(e);return t.w=0,t.n=0,t},re=e=>(e.w&ce)>0,se=e=>(e.n&ce)>0,ie=new WeakMap;let le=0,cLine truncated
|
||||
@@ -1125,7 +1125,7 @@ u, .underline {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#bar_ui {
|
||||
#click_form {
|
||||
float: left;
|
||||
min-width: 57%;
|
||||
}
|
||||
|
||||
@@ -126,6 +126,7 @@
|
||||
</header>
|
||||
|
||||
<div id="info_boxes">
|
||||
{% block info_boxes %}
|
||||
{% set sith = get_sith() %}
|
||||
{% if sith.alert_msg %}
|
||||
<div id="alert_box">
|
||||
@@ -137,6 +138,7 @@
|
||||
{{ sith.info_msg|markdown }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
||||
{% else %}{# if not popup #}
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
{% trans obj=object %}Edit {{ obj }}{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block info_boxes %}
|
||||
{% endblock %}
|
||||
|
||||
{% block nav %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>{% trans %}Make a cash register summary{% endtrans %}</h2>
|
||||
<form action="" method="post" id="cash_summary_form">
|
||||
|
||||
@@ -1,27 +1,16 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
{% from "core/macros.jinja" import user_mini_profile, user_subscription %}
|
||||
|
||||
|
||||
{% macro add_product(id, content, class="") %}
|
||||
<form method="post" action="{{ url('counter:click', counter_id=counter.id, user_id=customer.user.id) }}" class="{{ class }}">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="action" value="add_product">
|
||||
<button type="submit" name="product_id" value="{{ id }}"> {{ content|safe }} </button>
|
||||
</form>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro del_product(id, content, class="") %}
|
||||
<form method="post" action="{{ url('counter:click', counter_id=counter.id, user_id=customer.user.id) }}" class="{{ class }}">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="action" value="del_product">
|
||||
<button type="submit" name="product_id" value="{{ id }}"> {{ content }} </button>
|
||||
</form>
|
||||
{% endmacro %}
|
||||
|
||||
{% block title %}
|
||||
{{ counter }}
|
||||
{% endblock %}
|
||||
|
||||
{% block info_boxes %}
|
||||
{% endblock %}
|
||||
|
||||
{% block nav %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h4 id="click_interface">{{ counter }}</h4>
|
||||
|
||||
@@ -52,56 +41,57 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="bar_ui">
|
||||
<noscript>
|
||||
<p class="important">Javascript is required for the counter UI.</p>
|
||||
</noscript>
|
||||
<div id="click_form">
|
||||
<h5>{% trans %}Selling{% endtrans %}</h5>
|
||||
<div>
|
||||
|
||||
<div class="important">
|
||||
{% if request.session['too_young'] %}
|
||||
<p><strong>{% trans %}Too young for that product{% endtrans %}</strong></p>
|
||||
{% endif %}
|
||||
{% if request.session['not_allowed'] %}
|
||||
<p><strong>{% trans %}Not allowed for that product{% endtrans %}</strong></p>
|
||||
{% endif %}
|
||||
{% if request.session['no_age'] %}
|
||||
<p><strong>{% trans %}No date of birth provided{% endtrans %}</strong></p>
|
||||
{% endif %}
|
||||
{% if request.session['not_enough'] %}
|
||||
<p><strong>{% trans %}Not enough money{% endtrans %}</strong></p>
|
||||
{% endif %}
|
||||
<p v-for="error in errors"><strong>{{ error }}</strong></p>
|
||||
</div>
|
||||
<form method="post" action="{{ url('counter:click', counter_id=counter.id, user_id=customer.user.id) }}">
|
||||
|
||||
<form method="post" action="{{ url('counter:click', counter_id=counter.id, user_id=customer.user.id) }}" class="code_form" @submit.prevent="handle_code">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="action" value="code">
|
||||
<input type="input" name="code" value="" class="focus" id="code_field"/>
|
||||
<input type="submit" value="{% trans %}Go{% endtrans %}" />
|
||||
</form>
|
||||
<p>{% trans %}Basket: {% endtrans %}</p>
|
||||
|
||||
{% raw %}
|
||||
<ul>
|
||||
{% for id,infos in request.session['basket']|dictsort %}
|
||||
{% set product = counter.products.filter(id=id).first() %}
|
||||
{% set s = infos['qty'] * infos['price'] / 100 %}
|
||||
<li>{{ del_product(id, '-', "inline") }} {{ infos['qty'] + infos['bonus_qty'] }} {{ add_product(id, '+', "inline") }}
|
||||
{{ product.name }}: {{ "%0.2f"|format(s) }} €
|
||||
{% if infos['bonus_qty'] %}
|
||||
P
|
||||
{% endif %}
|
||||
<li v-for="p_info,p_id in basket">
|
||||
|
||||
<form method="post" action="" class="inline del_product_form" @submit.prevent="handle_action">
|
||||
<input type="hidden" name="csrfmiddlewaretoken" v-bind:value="js_csrf_token">
|
||||
<input type="hidden" name="action" value="del_product">
|
||||
<input type="hidden" name="product_id" v-bind:value="p_id">
|
||||
<button type="submit"> - </button>
|
||||
</form>
|
||||
|
||||
{{ p_info["qty"] + p_info["bonus_qty"] }}
|
||||
|
||||
<form method="post" action="" class="inline add_product_form" @submit.prevent="handle_action">
|
||||
<input type="hidden" name="csrfmiddlewaretoken" v-bind:value="js_csrf_token">
|
||||
<input type="hidden" name="action" value="add_product">
|
||||
<input type="hidden" name="product_id" v-bind:value="p_id">
|
||||
<button type="submit"> + </button>
|
||||
</form>
|
||||
|
||||
{{ products[p_id].name }}: {{ (p_info["qty"]*p_info["price"]/100).toLocaleString(undefined, { minimumFractionDigits: 2 }) }} € <span v-if="p_info['bonus_qty'] > 0">P</span>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<p><strong>{% trans %}Total: {% endtrans %}{{ "%0.2f"|format(basket_total) }} €</strong></p>
|
||||
<p>
|
||||
<strong>Total: {{ sum_basket().toLocaleString(undefined, { minimumFractionDigits: 2 }) }} €</strong>
|
||||
</p>
|
||||
{% endraw %}
|
||||
|
||||
<div class="important">
|
||||
{% if request.session['too_young'] %}
|
||||
<p><strong>{% trans %}Too young for that product{% endtrans %}</strong></p>
|
||||
{% endif %}
|
||||
{% if request.session['not_allowed'] %}
|
||||
<p><strong>{% trans %}Not allowed for that product{% endtrans %}</strong></p>
|
||||
{% endif %}
|
||||
{% if request.session['no_age'] %}
|
||||
<p><strong>{% trans %}No date of birth provided{% endtrans %}</strong></p>
|
||||
{% endif %}
|
||||
{% if request.session['not_enough'] %}
|
||||
<p><strong>{% trans %}Not enough money{% endtrans %}</strong></p>
|
||||
{% endif %}
|
||||
<p v-for="error in errors"><strong>{{ error }}</strong></p>
|
||||
</div>
|
||||
|
||||
<form method="post" action="{{ url('counter:click', counter_id=counter.id, user_id=customer.user.id) }}">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="action" value="finish">
|
||||
@@ -141,23 +131,89 @@
|
||||
{% else %}
|
||||
{% set file = static('core/img/na.gif') %}
|
||||
{% endif %}
|
||||
{% set prod = '<strong>%s</strong><hr><img src="%s" /><span>%s €<br>%s</span>' % (p.name, file, p.selling_price, p.code) %}
|
||||
{{ add_product(p.id, prod, "form_button") }}
|
||||
<form method="post" action="{{ url('counter:click', counter_id=counter.id, user_id=customer.user.id) }}" class="form_button add_product_form" @submit.prevent="handle_action">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="action" value="add_product">
|
||||
<input type="hidden" name="product_id" value="{{ p.id }}">
|
||||
<button type="submit"><strong>{{ p.name }}</strong><hr><img src="{{ file }}" /><span>{{ p.selling_price }} €<br>{{ p.code }}</span></button>
|
||||
</form>
|
||||
{%- endfor %}
|
||||
</div>
|
||||
{%- endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
<script>
|
||||
document.getElementById("click_interface").scrollIntoView();
|
||||
</script>
|
||||
{{ super() }}
|
||||
<script src="{{ static('core/js/vue.global.prod.js') }}"></script>
|
||||
<script>
|
||||
$( function() {
|
||||
var products = [
|
||||
/* Vue.JS dynamic form */
|
||||
const click_form_vue = Vue.createApp({
|
||||
data() {
|
||||
return {
|
||||
js_csrf_token: "{{ csrf_token }}",
|
||||
products: {
|
||||
{% for p in products -%}
|
||||
{{ p.id }}: {
|
||||
code: "{{ p.code }}",
|
||||
name: "{{ p.name }}",
|
||||
selling_price: "{{ p.selling_price }}",
|
||||
special_selling_price: "{{ p.special_selling_price }}",
|
||||
},
|
||||
{%- endfor %}
|
||||
},
|
||||
basket: {{ request.session["basket"]|tojson }},
|
||||
errors: [],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
sum_basket() {
|
||||
var vm = this;
|
||||
var total = 0;
|
||||
for(idx in vm.basket) {
|
||||
var item = vm.basket[idx];
|
||||
console.log(item);
|
||||
total += item["qty"] * item["price"];
|
||||
}
|
||||
return total / 100;
|
||||
},
|
||||
handle_code(event) {
|
||||
var vm = this;
|
||||
var code = $(event.target).find("#code_field").val().toUpperCase();
|
||||
console.log("Code:");
|
||||
console.log(code);
|
||||
if(code == "{% trans %}END{% endtrans %}" || code == "{% trans %}CAN{% endtrans %}") {
|
||||
$(event.target).submit();
|
||||
} else {
|
||||
vm.handle_action(event);
|
||||
}
|
||||
},
|
||||
handle_action(event) {
|
||||
var vm = this;
|
||||
var payload = $(event.target).serialize();
|
||||
$.ajax({
|
||||
type: 'post',
|
||||
dataType: 'json',
|
||||
data: payload,
|
||||
success: function(response) {
|
||||
vm.basket = response.basket;
|
||||
vm.errors = [];
|
||||
},
|
||||
error: function(error) {
|
||||
vm.basket = error.responseJSON.basket;
|
||||
vm.errors = error.responseJSON.errors;
|
||||
}
|
||||
});
|
||||
$('form.code_form #code_field').val("").focus();
|
||||
}
|
||||
}
|
||||
}).mount('#bar_ui');
|
||||
|
||||
/* Autocompletion in the code field */
|
||||
var products_autocomplete = [
|
||||
{% for p in products -%}
|
||||
{
|
||||
value: "{{ p.code }}",
|
||||
@@ -166,6 +222,7 @@ $( function() {
|
||||
},
|
||||
{%- endfor %}
|
||||
];
|
||||
|
||||
var quantity = "";
|
||||
var search = "";
|
||||
var pattern = /^(\d+x)?(.*)/i;
|
||||
@@ -183,21 +240,22 @@ $( function() {
|
||||
quantity = res[1] || "";
|
||||
search = res[2];
|
||||
var matcher = new RegExp( $.ui.autocomplete.escapeRegex( search ), "i" );
|
||||
response($.grep( products, function( value ) {
|
||||
response($.grep( products_autocomplete, function( value ) {
|
||||
value = value.tags;
|
||||
return matcher.test( value );
|
||||
}));
|
||||
},
|
||||
});
|
||||
});
|
||||
$( function() {
|
||||
$("#bar_ui").accordion({
|
||||
|
||||
/* Accordion UI between basket and refills */
|
||||
$("#click_form").accordion({
|
||||
heightStyle: "content",
|
||||
activate: function(event, ui){
|
||||
$(".focus").focus();
|
||||
}
|
||||
});
|
||||
$("#products").tabs();
|
||||
|
||||
$("#code_field").focus();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -12,6 +12,12 @@
|
||||
{% trans counter_name=counter %}{{ counter_name }} counter{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block info_boxes %}
|
||||
{% endblock %}
|
||||
|
||||
{% block nav %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h3>{% trans counter_name=counter %}{{ counter_name }} counter{% endtrans %}</h3>
|
||||
|
||||
|
||||
@@ -5,6 +5,12 @@
|
||||
{% trans counter_name=counter %}{{ counter_name }} last operations{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block info_boxes %}
|
||||
{% endblock %}
|
||||
|
||||
{% block nav %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h3>{% trans counter_name=counter %}{{ counter_name }} last operations{% endtrans %}</h3>
|
||||
<h4>{% trans %}Refillings{% endtrans %}</h4>
|
||||
|
||||
+14
-3
@@ -68,18 +68,29 @@ class CounterTest(TestCase):
|
||||
location,
|
||||
{
|
||||
"action": "refill",
|
||||
"amount": "10",
|
||||
"amount": "5",
|
||||
"payment_method": "CASH",
|
||||
"bank": "OTHER",
|
||||
},
|
||||
)
|
||||
response = self.client.post(location, {"action": "code", "code": "BARB"})
|
||||
response = self.client.post(
|
||||
location, {"action": "add_product", "product_id": "4"}
|
||||
)
|
||||
response = self.client.post(
|
||||
location, {"action": "del_product", "product_id": "4"}
|
||||
)
|
||||
response = self.client.post(location, {"action": "code", "code": "2xdeco"})
|
||||
response = self.client.post(location, {"action": "code", "code": "1xbarb"})
|
||||
response = self.client.post(location, {"action": "code", "code": "fin"})
|
||||
|
||||
response_get = self.client.get(response.get("location"))
|
||||
response_content = response_get.content.decode("utf-8")
|
||||
self.assertTrue("<li>2 x Barbar" in str(response_content))
|
||||
self.assertTrue("<li>2 x Déconsigne Eco-cup" in str(response_content))
|
||||
self.assertTrue(
|
||||
"<p>Client : Richard Batsbak - Nouveau montant : 8.30"
|
||||
in str(response_get.content)
|
||||
"<p>Client : Richard Batsbak - Nouveau montant : 3.60"
|
||||
in str(response_content)
|
||||
)
|
||||
|
||||
|
||||
|
||||
+33
-2
@@ -38,7 +38,7 @@ from django.views.generic.edit import (
|
||||
from django.forms.models import modelform_factory
|
||||
from django.forms import CheckboxSelectMultiple
|
||||
from django.urls import reverse_lazy, reverse
|
||||
from django.http import HttpResponseRedirect, HttpResponse
|
||||
from django.http import HttpResponseRedirect, HttpResponse, JsonResponse
|
||||
from django.utils import timezone
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
@@ -48,6 +48,7 @@ from django.db import DataError, transaction, models
|
||||
import re
|
||||
import pytz
|
||||
from datetime import date, timedelta, datetime
|
||||
from http import HTTPStatus
|
||||
from ajax_select.fields import AutoCompleteSelectField, AutoCompleteSelectMultipleField
|
||||
from ajax_select import make_ajax_field
|
||||
|
||||
@@ -357,6 +358,34 @@ class CounterClick(CounterTabsMixin, CanViewMixin, DetailView):
|
||||
pk_url_kwarg = "counter_id"
|
||||
current_tab = "counter"
|
||||
|
||||
def render_to_response(self, *args, **kwargs):
|
||||
if self.request.is_ajax(): # JSON response for AJAX requests
|
||||
response = {"errors": []}
|
||||
status = HTTPStatus.OK
|
||||
|
||||
if self.request.session["too_young"]:
|
||||
response["errors"].append(_("Too young for that product"))
|
||||
status = HTTPStatus.UNAVAILABLE_FOR_LEGAL_REASONS
|
||||
if self.request.session["not_allowed"]:
|
||||
response["errors"].append(_("Not allowed for that product"))
|
||||
status = HTTPStatus.FORBIDDEN
|
||||
if self.request.session["no_age"]:
|
||||
response["errors"].append(_("No date of birth provided"))
|
||||
status = HTTPStatus.UNAVAILABLE_FOR_LEGAL_REASONS
|
||||
if self.request.session["not_enough"]:
|
||||
response["errors"].append(_("Not enough money"))
|
||||
status = HTTPStatus.PAYMENT_REQUIRED
|
||||
|
||||
if len(response["errors"]) > 1:
|
||||
status = HTTPStatus.BAD_REQUEST
|
||||
|
||||
response["basket"] = self.request.session["basket"]
|
||||
|
||||
return JsonResponse(response, status=status)
|
||||
|
||||
else: # Standard HTML page
|
||||
return super().render_to_response(*args, **kwargs)
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.customer = get_object_or_404(Customer, user__id=self.kwargs["user_id"])
|
||||
obj = self.get_object()
|
||||
@@ -370,7 +399,9 @@ class CounterClick(CounterTabsMixin, CanViewMixin, DetailView):
|
||||
)
|
||||
or len(obj.get_barmen_list()) < 1
|
||||
):
|
||||
raise PermissionDenied
|
||||
return HttpResponseRedirect(
|
||||
reverse_lazy("counter:details", kwargs={"counter_id": obj.id})
|
||||
)
|
||||
else:
|
||||
if not request.user.is_authenticated:
|
||||
raise PermissionDenied
|
||||
|
||||
Reference in new issue
Block a user