Commit 191dc696 by François C.

Merge branch 'adaptation_supercafoutch' into adaptation_supercoop_supercafoutch

parents c805631f c1c80f59
Pipeline #2360 passed with stage
in 1 minute 22 seconds
......@@ -1339,7 +1339,7 @@ class CagetteServices(models.Model):
@staticmethod
def get_services_at_time(time, tz_offset, with_members=True):
"""Retrieve present services with member linked."""
"""Retrieve present services with members linked."""
default_acceptable_minutes_after_shift_begins = getattr(settings, 'ACCEPTABLE_ENTRANCE_MINUTES_AFTER_SHIFT_BEGINS', 15)
minutes_before_shift_starts_delay = getattr(settings, 'ACCEPTABLE_ENTRANCE_MINUTES_BEFORE_SHIFT', 15)
......@@ -1360,7 +1360,7 @@ class CagetteServices(models.Model):
fields = ['name', 'week_number', 'registration_ids',
'standard_registration_ids',
'shift_template_id', 'shift_ticket_ids',
'date_begin_tz', 'date_end_tz']
'date_begin_tz', 'date_end_tz', 'state']
services = api.search_read('shift.shift', cond, fields,order ="date_begin_tz ASC")
for s in services:
if (len(s['registration_ids']) > 0):
......@@ -1510,13 +1510,18 @@ class CagetteServices(models.Model):
cond = [['date_begin', '>=', date_24h_before.isoformat()],
['date_begin', '<=', end_date.isoformat()],
['state', '=', 'open']]
fields = ['state', 'partner_id', 'date_begin']
fields = ['state', 'partner_id', 'date_begin', 'shift_id']
res = api.search_read('shift.registration', cond, fields)
ids = []
partner_ids = []
excluded_partner = []
canceled_reg_ids = [] # for exempted people
shift_ids = []
for r in res:
partner_ids.append(int(r['partner_id'][0]))
shift_id = int(r['shift_id'][0])
if shift_id not in shift_ids:
shift_ids.append(shift_id)
cond = [['id', 'in', partner_ids],
['cooperative_state', 'in', ['exempted']]]
fields = ['id']
......@@ -1530,13 +1535,28 @@ class CagetteServices(models.Model):
(_h, _m, _s) = h.split(':')
if int(_h) < 21:
ids.append(int(r['id']))
else:
canceled_reg_ids.append(int(r['id']))
# coop_logger.info("Traitement absences shift_registration ids %s", ids)
f = {'state': absence_status, 'date_closed': now.isoformat()}
update_shift_reg_result = {'update': api.update('shift.registration', ids, f), 'reg_shift': res}
update_shift_reg_result = {'update': api.update('shift.registration', ids, f), 'reg_shift': res, 'errors': []}
if update_shift_reg_result['update'] is True:
update_shift_reg_result['process_status_res'] = api.execute('res.partner','run_process_target_status', [])
# change shift state by triggering button_done method for all related shifts
if len(canceled_reg_ids) > 0:
f = {'state': 'cancel', 'date_closed': now.isoformat()}
api.update('shift.registration', canceled_reg_ids, f)
for sid in shift_ids:
try:
api.execute('shift.shift', 'button_done', sid)
except Exception as e:
marshal_none_error = 'cannot marshal None unless allow_none is enabled'
if not (marshal_none_error in str(e)):
update_shift_reg_result['errors'].append({'shift_id': sid, 'msg' :str(e)})
return update_shift_reg_result
@staticmethod
def close_ftop_service():
"""Called by cron script"""
......@@ -1670,6 +1690,104 @@ class CagetteServices(models.Model):
coop_logger.error("easy_validate_shift_presence : %s %s", str(coop_id), str(e))
return res
class CagetteService(models.Model):
"""Class to handle cagette Odoo service."""
def __init__(self, id):
"""Init with odoo id."""
self.id = int(id)
self.o_api = OdooAPI()
def _process_associated_people_extra_shift_done(self):
cond = [['shift_id', '=', self.id],
['state', '=', 'done'],
['associate_registered', '=', 'both'],
['should_increment_extra_shift_done', '=', True]]
fields = ['id', 'state', 'partner_id', 'date_begin']
res = self.o_api.search_read('shift.registration', cond, fields)
extra_shift_done_incremented_srids = [] # shift registration ids
for r in res:
cond = [['id', '=', r['partner_id'][0]]]
fields = ['id','extra_shift_done']
res_partner = self.o_api.search_read('res.partner', cond, fields)
f = {'extra_shift_done': res_partner[0]['extra_shift_done'] + 1 }
self.o_api.update('res.partner', [r['partner_id'][0]], f)
extra_shift_done_incremented_srids.append(int(r['id']))
# Make sure the counter isn't incremented twice
f = {'should_increment_extra_shift_done': False}
self.o_api.update('shift.registration', extra_shift_done_incremented_srids, f)
def _process_related_shift_registrations(self):
now = datetime.datetime.now()
absence_status = 'excused'
res_c = self.o_api.search_read('ir.config_parameter',
[['key', '=', 'lacagette_membership.absence_status']],
['value'])
if len(res_c) == 1:
absence_status = res_c[0]['value']
cond = [['shift_id', '=', self.id],
['state', '=', 'open']]
fields = ['state', 'partner_id', 'date_begin']
res = self.o_api.search_read('shift.registration', cond, fields)
ids = []
partner_ids = []
excluded_partner = []
canceled_reg_ids = [] # for exempted people
for r in res:
partner_ids.append(int(r['partner_id'][0]))
cond = [['id', 'in', partner_ids],
['cooperative_state', 'in', ['exempted']]]
fields = ['id']
res_exempted = self.o_api.search_read('res.partner', cond, fields)
for r in res_exempted:
excluded_partner.append(int(r['id']))
for r in res:
if not (int(r['partner_id'][0]) in excluded_partner):
d_begin = r['date_begin']
(d, h) = d_begin.split(' ')
(_h, _m, _s) = h.split(':')
if int(_h) < 21:
ids.append(int(r['id']))
else:
canceled_reg_ids.append(int(r['id']))
# coop_logger.info("Traitement absences shift_registration ids %s", ids)
f = {'state': absence_status, 'date_closed': now.isoformat()}
update_shift_reg_result = {'update': self.o_api.update('shift.registration', ids, f), 'reg_shift': res, 'errors': []}
if update_shift_reg_result['update'] is True:
update_shift_reg_result['process_status_res'] = self.o_api.execute('res.partner','run_process_target_status', [])
# change shift state by triggering button_done method for all related shifts
if len(canceled_reg_ids) > 0:
f = {'state': 'cancel', 'date_closed': now.isoformat()}
self.o_api.update('shift.registration', canceled_reg_ids, f)
try:
self.o_api.execute('shift.shift', 'button_done', self.id)
except Exception as e:
marshal_none_error = 'cannot marshal None unless allow_none is enabled'
if not (marshal_none_error in str(e)):
update_shift_reg_result['errors'].append({'shift_id': self.id, 'msg' :str(e)})
return update_shift_reg_result
def record_absences(self, request):
"""Can only been executed if an Odoo user is beeing connected."""
res = {}
try:
if CagetteUser.are_credentials_ok(request) is True:
self._process_associated_people_extra_shift_done()
res = self._process_related_shift_registrations()
else:
res['error'] = 'Forbidden'
except Exception as e:
coop_logger.error("CagetteService.record_absences : %s %s", str(self.id), str(e))
res['error'] = str(e)
return res
class CagetteUser(models.Model):
@staticmethod
......
......@@ -49,6 +49,7 @@ h1 .member_name {font-weight: bold;}
.members_list li.btn--inverse.late {background-color: #de9b00; color: white}
.members_list li.btn--inverse.both {background-color: #0275d8 ; color: white}
.members_list.done li.btn {pointer-events: none;}
#service_entry_success {font-size: x-large;}
#service_entry_success .explanations {margin: 25px 0; font-size: 18px;}
#service_entry_success .points,
......
......@@ -41,6 +41,7 @@ var coop_info = $('.coop-info');
var service_data = null;
const missed_begin_msg = $('#missed_begin_msg').html();
const current_shift_process_data_actions = $('#current_shift_process_data_actions');
let no_pict_msg = $('#no-picture-msg');
......@@ -70,6 +71,12 @@ var html_elts = {
var chars = []; //input chars buffer
var reset_shift_process_actions_zone = function() {
current_shift_process_data_actions.off('click', 'a');
current_shift_process_data_actions.hide();
current_shift_process_data_actions.empty();
}
function fill_member_slide(member) {
no_pict_msg.hide();
current_displayed_member = member;
......@@ -282,6 +289,9 @@ function fill_service_entry(s) {
// if (typeof s.late != "undefined" && s.late == true) {
// m_list = '<ul class="members_list late">';
// }
if (s.state == 'done') {
m_list = '<ul class="members_list done">';
}
$.each(s.members, function(i, e) {
var li_class = "btn";
var li_data = "";
......@@ -304,6 +314,9 @@ function fill_service_entry(s) {
} else {
li_data = ' data-rid="'+e.id+'" data-mid="'+e.partner_id[0]+'"';
}
if (s.state == 'done') {
li_data += ' disabled ';
}
m_list += '<li class="'+li_class+'" '+li_data+'>';
m_list += e.partner_id[1];
m_list += '</li>';
......@@ -311,6 +324,45 @@ function fill_service_entry(s) {
m_list += '</ul>';
}
if (coop_is_connected()) {
// Add shift process data
reset_shift_process_actions_zone();
if (s.state == 'draft' || s.state == 'confirm') {
let btn = $('<a>').addClass('btn btn--primary txtcenter')
.text('Enregistrer les absences / présences')
.attr('id','record_shift_absences');
current_shift_process_data_actions.append(btn);
current_shift_process_data_actions.on('click', '#record_shift_absences', function(){
msg = "<p>Lancer le traitement des présences et absences de ce service</p>";
openModal(msg, function() {
btn.attr('disabled', 'true')
try {
$.ajax({
url: '/members/record_shift_absences/' + s.id,
dataType : 'json'
})
.done(function(rData) {
if (typeof rData.res.update !== "undefined" && rData.res.update == true) {
enqueue_message_for_next_loading("Données de présences traitées.");
location.reload();
} else {
closeModal();
btn.removeAttr('disabled');
alert(JSON.stringify(rData.res));
}
});
} catch (e) {
console.log(e);
}
}, 'Confirmer');
});
} else {
current_shift_process_data_actions.append("<em>Traitement des présences : " + s.state + "</em>");
}
current_shift_process_data_actions.show();
}
rattrapage_ou_volant = null;
shift_members.html(m_list);
rattrapage_wanted.show();
......@@ -401,6 +453,8 @@ function get_service_entry_data() {
})
.done(function(rData) {
info_place.text('');
reset_shift_process_actions_zone();
var page_title = pages.service_entry.find('h1');
page_title.text('Qui es-tu ?');
......
......@@ -43,6 +43,7 @@ urlpatterns = [
url(r'^services_at_time/([0-9TZ\-\: \.]+)/([0-9\-]+)$', views.services_at_time),
url(r'^service_presence/$', views.record_service_presence),
url(r'^record_absences/?([0-9\-\ \:]*)$', views.record_absences),
url(r'^record_shift_absences/?([0-9]+)$', views.record_shift_absences),
url(r'^close_ftop_service$', views.close_ftop_service),
url(r'^get_credentials$', views.get_credentials),
url(r'^remove_data_from_couchdb$', views.remove_data_from_CouchDB),
......
......@@ -5,7 +5,7 @@ from outils.for_view_imports import *
from members.models import CagetteMember
from members.models import CagetteUser
from members.models import CagetteMembers
from members.models import CagetteServices
from members.models import CagetteServices, CagetteService
from outils.forms import GenericExportMonthForm
import datetime
......@@ -105,6 +105,7 @@ def inscriptions(request, type=1):
'show_ftop_button': getattr(settings, 'SHOW_FTOP_BUTTON', True),
'db': settings.COUCHDB['dbs']['member'],
'ASSOCIATE_MEMBER_SHIFT' : getattr(settings, 'ASSOCIATE_MEMBER_SHIFT', ''),
'can_create_binome': getattr(settings, 'CAN_CREATE_BINOME', True),
'prepa_odoo_url' : getattr(settings, 'PREPA_ODOO_URL', '/members/prepa-odoo'),
'committees_shift_id': committees_shift_id,
}
......@@ -347,6 +348,10 @@ def easy_validate_shift_presence(request):
def record_absences(request, date):
return JsonResponse({'res': CagetteServices.record_absences(date)})
def record_shift_absences(request, id):
shift = CagetteService(id)
return JsonResponse({'res': shift.record_absences(request)})
def close_ftop_service(request):
"""Close the closest past FTOP service"""
return JsonResponse({'res': CagetteServices.close_ftop_service()})
......
......@@ -39,6 +39,7 @@
justify-content: space-between;
}
@media screen and (max-width:992px) {
#calendar_top_info {
display: flex;
......
var calendar = null,
selected_shift = null,
vw = null;
vw = null,
adding_mode = false;
/* - Logic */
......@@ -51,6 +52,9 @@ function add_or_change_shift(new_shift_id) {
if (selected_shift === null) {
tUrl = '/shifts/add_shift';
if (partner_data.makeups_to_do > 0) {
tData += '&is_makeup=1';
}
} else {
tUrl = '/shifts/change_shift';
tData = tData + '&idOldShift='+ selected_shift.shift_id[0] +'&idRegister=' + selected_shift.id;
......@@ -143,6 +147,8 @@ function add_or_change_shift(new_shift_id) {
}, 300);
}
});
adding_mode = false;
$('#start_adding_shift').prop('disabled', false);
}
return null;
......@@ -315,6 +321,7 @@ function init_shifts_list() {
if (!can_exchange_shifts()) {
shift_line_template.find(".selectable_shift_line").addClass("btn");
shift_line_template.find(".checkbox").prop("disabled", "disabled");
$('#start_adding_shift').prop('disabled', true);
} else {
if (shift.is_makeup==true) {
shift_line_template.find(".selectable_shift_line").addClass("btn--warning");
......@@ -577,12 +584,27 @@ function init_calendar_page() {
"Valider"
);
} else if (selected_shift === null && can_exchange_shifts()) {
/* could exchange shift but no old shift selected */
openModal(
"Je dois sélectionner un service à échanger.",
closeModal,
"J'ai compris"
);
if (adding_mode === false) {
/* could exchange shift but no old shift selected */
openModal(
"Je dois sélectionner un service à échanger.",
closeModal,
"J'ai compris"
);
} else {
// Display modal
let modal_template = $("#modal_add_shift_template");
modal_template.find(".date_new_shift").text(new_shift_date);
modal_template.find(".time_new_shift").text(new_shift_time);
openModal(
modal_template.html(),
() => {
add_or_change_shift(new_shift_id);
},
"Valider"
);
}
} else if (should_select_makeup()) {
/* choose a makeup service */
// Check if selected new shift is in less than 6 months
......@@ -811,6 +833,19 @@ function init_shifts_exchange() {
init_calendar_page();
}
$('#start_adding_shift').click((c) => {
openModal(
"<p>Je souhaite sélectionner un service supplémentaire.</p>",
() => {
$(c.target).prop('disabled', true);
adding_mode = true;
closeModal();
},
"Confirmer",
false
);
});
$(window).smartresize(function() {
// only apply if a width threshold is passed
if (
......
......@@ -130,6 +130,8 @@ def index(request, exception=None):
if hasattr(settings, 'SHIFT_EXCHANGE_DAYS_TO_HIDE'):
days_to_hide = settings.SHIFT_EXCHANGE_DAYS_TO_HIDE
context['daysToHide'] = days_to_hide
can_add_shift = getattr(settings, 'CAN_ADD_SHIFT', False)
context['canAddShift'] = "true" if can_add_shift is True else "false"
msettings = MConfig.get_settings('members')
context['forms_link'] = msettings['forms_link']['value'] if 'forms_link' in msettings else ''
......@@ -169,7 +171,7 @@ def home(request):
Consequently, the front-end url should be unknown from the server so the user is redirected to the index,
then the front-end index will call this endpoint to load the home page
"""
template = loader.get_template('members_space/home.html')
template = loader.get_template(getattr(settings, 'MEMBERS_SPACE_HOME_TEMPLATE', 'members_space/home.html'))
context = {
'title': 'Espace Membres',
}
......@@ -203,6 +205,7 @@ def shifts_exchange(request):
template = loader.get_template('members_space/shifts_exchange.html')
context = {
'title': 'Échange de Services',
'canAddShift': getattr(settings, 'CAN_ADD_SHIFT', False)
}
return HttpResponse(template.render(context, request))
......
......@@ -131,6 +131,10 @@
La Cagette use False to implement custom rules
- CAN_CREATE_BINOME = True (by default)
If set to False, in new member creation form, a member can be selected to be associated with.
- ASSOCIATE_MEMBER_SHIFT = ''
Id number of the associate shift template
......@@ -326,6 +330,11 @@
- MEMBERS_SPACE_FAQ_TEMPLATE = None
If set to None, "FAQ menu" will not be shown. To use a custom content add a template and set it's relative path
- MEMBERS_SPACE_HOME_TEMPLATE = 'members_space/supercafoutch/home.html'
If not set, 'members_space/home.html' (la Cagette)
- MEMBERS_SPACE_SHOW_UNDERSTAND_MY_STATUS = False
By default, is True. If False, tile showing explanations is not shown
......@@ -333,6 +342,10 @@
- BLOCK_ACTIONS_FOR_ATTACHED_PEOPLE = False
Attached people can or not change his services
- CAN_ADD_SHIFT = True
By default, False. Set if coop can or not add shifts in their memberspace calendar
### Reception
- RECEPTION_ADD_ADMIN_MODE = True
......
......@@ -169,8 +169,8 @@ class CagetteShift(models.Model):
"origin": 'memberspace',
"is_makeup": data['is_makeup'],
"state": 'open'}
if shift_type == "standard" and data['is_makeup'] is not True:
fieldsDatas['template_created'] = 1 # It's not true but otherwise, presence add 1 standard point, which is not wanted
if (shift_type == "standard" and data['is_makeup'] is not True) or shift_type == "ftop":
fieldsDatas['template_created'] = 1 # It's not true but otherwise, presence add 1 standard point , which is not wanted
st_r_id = self.o_api.create('shift.registration', fieldsDatas)
except Exception as e:
......
......@@ -281,8 +281,11 @@ def add_shift(request):
"idPartner": int(request.POST['idPartner']),
"idShift":int(request.POST['idNewShift']),
"shift_type":request.POST['shift_type'],
"is_makeup":True
"is_makeup": False
}
if 'is_makeup' in request.POST and request.POST['is_makeup'] == "1":
data['is_makeup'] = True
#Insertion du nouveau shift
st_r_id = False
......
......@@ -365,7 +365,17 @@ class CagetteStock(models.Model):
return res
@staticmethod
def get_valuable_stock():
articles = []
try:
api = OdooAPI()
cond = [['qty_available','>', 0], ['active', '=', True]]
fields = ["barcode", "display_name", "qty_available", "standard_price"]
articles = api.search_read('product.product', cond, fields, 1000000)
except Exception as e:
coop_logger.error("Erreur get_valuable_stock : %s", str(e))
return articles
def set_test():
o_api = OdooAPI()
......
$(document).ready(function() {
table_article = $('#tableArticle').DataTable({
"ajax": {
"url": "get_valuable_stock",
"data": ""
},
"columns":[
{data:"barcode", "title":"Code-barre", "width": "50%"},
{data:"display_name", "title":"Article", "width": "50%"},
{data:"qty_available", "title":"Stock", "width":"15%"
},
{data:"standard_price", "title":"Prix achat", "width":"15%"
}
],
"searching": true,
"order": [
[
2,
"desc"
]
],
"iDisplayLength": 50,
"language": {
"emptyTable": "Pas de donnée",
"info": "Affiché : lignes _START_ à _END_ sur _TOTAL_",
"infoEmpty": "Affiché : 0 ligne",
"infoFiltered": "(filtré de _MAX_ lignes au total)",
"thousands": ",",
"lengthMenu": "Afficher _MENU_ lignes",
"loadingRecords": "Loading...",
"processing": "Processing...",
"search": "Rechercher un article :",
"searchPlaceholder": "Référence, code-barre",
"zeroRecords": "Aucun résultat",
"paginate": {
"first": "Premier",
"last": "Dernier",
"next": "Suivant",
"previous": "Precedant"
},
"aria": {
"sortAscending": ": activate to sort column ascending",
"sortDescending": ": activate to sort column descending"
}
},
buttons: [
{
extend: 'excelHtml5',
text: 'Export en Excel',
className: 'btn--primary btn_export'
},
],
dom: '<lr<t>ip><"clear"><B>',
});
});
\ No newline at end of file
......@@ -46,4 +46,8 @@ urlpatterns = [
url(r'^get_saleWitheNotSale', views.get_saleWitheNotSale),
url(r'^get_test', views.get_test),
# Values
url(r'^stockValues', views.stockValues),
url(r'^get_valuable_stock', views.get_valuable_stock),
]
......@@ -550,8 +550,16 @@ def get_saleWitheNotSale(request):
return JsonResponse({"data":lArticleSale}, safe=True)
def stockValues(request):
"""Page valeurs du stock (quantités positives)."""
context = {'title': 'Stock (quantités positives valorisées)'}
template = loader.get_template('stock/stock_values.html')
return HttpResponse(template.render(context, request))
def get_valuable_stock(request):
articles = CagetteStock.get_valuable_stock()
return JsonResponse({"data":articles}, safe=True)
def get_test(request):
res = CagetteStock.get_sale_qty_by_from(1)
return JsonResponse({"data":res}, safe=False)
......@@ -141,7 +141,9 @@
<div class="col-2 row-2">
<a class="btn btn--primary" data-next="first_page" >Retour accueil</a>
</div>
<div class="col-2 row-2"></div>
<div class="col-2 row-2 txtcenter">
<div id="current_shift_process_data_actions" style="display:none;"></div>
</div>
<div class="col-2 row-2 login_area">
{% include "common/conn_admin.html" %}
</div>
......
......@@ -79,16 +79,18 @@
</p>
{% endif %}
{% if ASSOCIATE_MEMBER_SHIFT %}
{% if can_create_binome %}
<p id="add_binome" >+ Binomes (facultatif)</p>
<div id="associate_area" style="display:none;">
<div class="choice_button_area d-flex" >
<div id="existing_member_choice" class="member_choice">
A mettre en binome avec un.e membre existant.e
</div>
{% if ASSOCIATE_MEMBER_SHIFT %}
<div id="new_member_choice" class="member_choice">
A mettre en binome avec un.e nouveau membre
</div>
{% endif %}
</div>
<div id="existing_member_choice_action" style="display:none;">
......@@ -110,6 +112,7 @@
</div>
</div>
</div>
{% if ASSOCIATE_MEMBER_SHIFT %}
<div id="new_member_choice_action" style="display:none;">
<div >
<div>
......@@ -117,6 +120,7 @@
</div>
</div>
</div>
{% endif %}
</div>
{% endif %}
<div>
......
......@@ -126,7 +126,7 @@
var days_to_hide = "{{daysToHide}}"
var partner_data = {
"partner_id":"{{partnerData.id}}",
"name":"{{partnerData.display_name}}",
"name":"{{partnerData.display_name|safe}}",
"shift_type":"{{partnerData.shift_type}}",
"date_delay_stop":"{{partnerData.date_delay_stop}}",
"cooperative_state":"{{partnerData.cooperative_state}}",
......@@ -134,25 +134,26 @@
"can_have_delay" : "{{partnerData.can_have_delay}}",
"makeups_to_do" : "{{partnerData.makeups_to_do}}",
"barcode_base" : "{{partnerData.barcode_base}}",
"street" : "{{partnerData.street}}",
"street2" : "{{partnerData.street2}}",
"street" : "{{partnerData.street|safe}}",
"street2" : "{{partnerData.street2|safe}}",
"zip" : "{{partnerData.zip}}",
"city" : "{{partnerData.city}}",
"city" : "{{partnerData.city|safe}}",
"mobile" : "{{partnerData.mobile}}",
"phone" : "{{partnerData.phone}}",
"email" : "{{partnerData.email}}",
"is_associated_people" : "{{partnerData.is_associated_people}}",
"parent_id" : "{{partnerData.parent_id}}",
"parent_name" : "{{partnerData.parent_name}}",
"parent_name" : "{{partnerData.parent_name|safe}}",
"parent_verif_token" : "{{partnerData.parent_verif_token}}",
"associated_partner_id" : "{{partnerData.associated_partner_id}}",
"associated_partner_name" : "{{partnerData.associated_partner_name}}",
"associated_partner_name" : "{{partnerData.associated_partner_name|safe}}",
"verif_token" : "{{partnerData.verif_token}}",
"leave_stop_date": "{{partnerData.leave_stop_date}}",
"comite": "{{partnerData.comite}}",
"extra_shift_done": parseInt("{{partnerData.extra_shift_done}}", 10)
};
var block_actions_for_attached_people = '{{block_actions_for_attached_people}}';
const canAddShift = {{canAddShift}};
</script>
<script src="{% static "js/all_common.js" %}?v=1651853225"></script>
<script src="{% static "js/members-space-home.js" %}?v=1651853225"></script>
......
......@@ -50,6 +50,9 @@
<i class="fas fa-spinner fa-spin fa-lg"></i>
</div>
<div id="shifts_list"></div>
{% if canAddShift %}
<button class="btn--primary selectable_shift_line" id="start_adding_shift"><strong>+ Ajouter un service</strong></button>
{% endif %}
</div>
<div id="calendar_explaination_area"></div>
<button id="calendar_explaination_button" class="btn--success">Légende du calendrier</button>
......
<div id="home">
<div class="page_title txtcenter">
<h1>Espace Membre</h1>
</div>
<div class="tiles_container">
<div class="tile high_tile" id="home_tile_my_info">
<div class="tile_title">
<i class="fas fa-user tile_icon"></i>
<span class="member_info member_name"></span>
</div>
<div class="tile_content">
{# <p><span class="member_info member_name"></span></p> #}
<p class="member_status_text_container">Mon statut : <span class="member_info member_status"></span></p>
<div class="delay_date_stop_container">
( jusqu'au <span class="delay_date_stop"></span> )
</div>
<div id="member_status_action">
<a href="#" target="_blank" class="btn--warning unsuscribed_form_link">
J'accède au formulaire
</a>
<button type="button" class="btn--danger choose_makeups">
Je sélectionne mes rattrapages
</button>
<button type="button" class="btn--success remove_future_registration">
J'ai validé un service à deux, je peux supprimer une présence
</button>
</div>
<div class="member_shift_name_area">
<span>Mon créneau : </span>
<span class="member_shift_name member_info"></span>
</div>
<div class="member_coop_number_area">
<span>Mon numéro de coop : </span>
<span class="member_coop_number member_info"></span>
</div>
<div class="member_associated_partner_area">
<span>Je suis en binôme avec : </span>
<span class="member_associated_partner member_info"></span>
</div>
<div id="see_more_info">
<button type="button", class="btn btn--primary home_link_button" id="see_more_info_link">
Accéder à mes infos et comprendre mon statut
</button>
</div>
</div>
</div>
<div class="tile high_tile" id="home_tile_my_services">
<div class="tile_title">
<i class="fas fa-clipboard tile_icon"></i>
Mes Services
</div>
<div class="tile_content">
<h3>Services à venir</h3>
<div id="home_incoming_services">
<i class="fas fa-spinner fa-spin fa-lg"></i>
</div>
<div id="go_to_shift_history_area">
<button type="button", class="btn btn--primary" id="home_go_to_shift_history">
Accéder à mon historique
</button>
</div>
</div>
</div>
<div class="tile small_tile" id="home_tile_services_exchange">
<div class="tile_title">
<i class="fas fa-exchange-alt tile_icon"></i>
Échange de services
</div>
<div class="tile_content">
<div>
Un empêchement ? J'anticipe et déplace mes services jusqu'à 24h avant leur début !
</div>
<div class="home_link_button_area">
<button type="button" class="btn--primary home_link_button" id="go_to_shifts_calendar">
Accéder au calendrier d'échange de services
</button>
</div>
</div>
</div>
<div class="tile small_tile" id="home_tile_help">
<div class="tile_title">
<i class="fas fa-question-circle tile_icon"></i>
J'ai une demande
</div>
<div class="tile_content">
<div class="home_link_button_area">
<a
href="javascript:void(0);"
class="btn--primary home_link_button"
id="go_to_forms"
>
Accéder à la FAQ
</a>
</div>
</div>
</div>
<div class="tile small_tile" id="home_tile_shop_info">
<div class="tile_title">
<i class="fas fa-newspaper tile_icon"></i>
Informations magasins
</div>
<div id="shop_info_content">
<div class="shop_info_item shop_opening_hours">
<div class="shop_info_item_content">
<div class="opening_hours_title">
Horaires du magasin :
</div>
<div class="opening_hours_content">
{{shop_opening_hours|safe}}
</div>
</div>
</div>
<div class="shop_info_item shop_message">
<div class="shop_info_item_content shop_message_content">
{{msg_accueil|safe}}
</div>
</div>
</div>
</div>
</div>
</div>
......@@ -31,6 +31,7 @@
<a class="dropdown-item" href="breakingArticleSet">Mettre en rupture un article sur odoo</a>
<a class="dropdown-item" href="stockQuantLastSale">Date de la dernière vente des articles</a>
<a class="dropdown-item" href="saleWithNotSale">Vente avec jours sans vente</a>
<a class="dropdown-item" href="stockValues">Stock (qtés > 0 valorisées)</a>
</div>
</li>
</ul>
......
{% extends "stock/stock_menu.html" %}
{% load static %}
{% block additionnal_css %}
<link rel="stylesheet" href="{% static 'css/datatables/jquery.dataTables.css' %}">
{% endblock %}
{% block additionnal_scripts %}
<script type="text/javascript" src="{% static 'js/datatables/jquery.dataTables.min.js' %}"></script>
<script type="text/javascript" src="{% static 'js/datatables/dataTables.plugins.js' %}"></script>
<script type="text/javascript" src="{% static 'js/datatables/datatables.buttons.min.js' %}"></script>
<script type="text/javascript" src="{% static 'js/datatables/buttons.html5.min.js' %}"></script>
<script type="text/javascript" src="{% static 'js/datatables/jszip.min.js' %}"></script>
<script type="text/javascript" src="{% static 'js/stock_values.js' %}"></script>
{% endblock %}
{% block content %}
<h1>Stock valorisé</h1>
<br>
<div class="main">
<table id="tableArticle" class="display" width="95%" cellspacing="0" ></table>
</div>
<br/>
<br/>
<script src="{% static "js/all_common.js" %}?v=1651853225"></script>
<script src="{% static "js/common.js" %}?v=1651853225"></script>
{% endblock %}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment