Commit 3f9684a6 by Damien Moulard

Merge branch 'revert-b190df6e' into 'dev_principale'

Revert "merge dev_cooperatic into dev_principale"

See merge request !100
parents b190df6e df42ebaf
Pipeline #1708 passed with stage
in 1 minute 38 seconds
......@@ -109,12 +109,3 @@ RECEPTION_PB = "Ici, vous pouvez signaler toute anomalie lors d'une réception,
# display or not column "Autres" in reception process
DISPLAY_COL_AUTRES = False
# Should block service exchange if old service is happening in less than 24h
BLOCK_SERVICE_EXCHANGE_24H_BEFORE = True
# URL to the metabase dashboard for orders helper
ORDERS_HELPER_METABASE_URL = "url_meta_base"
# New members space
USE_NEW_MEMBERS_SPACE = True
START_DATE_FOR_SHIFTS_HISTORY = "2018-01-01"
AMNISTIE_DATE= "2021-11-24 00:00:00"
......@@ -91,7 +91,7 @@ class CagetteEnvelops(models.Model):
if not ('error' in res):
try:
if int(float(data['amount']) * 100) == int(float(invoice['residual_signed']) * 100):
# This payment is what was left to pay, so change invoice state
# This payment is what it was left to pay, so change invoice state
self.o_api.update('account.invoice', [invoice['id']], {'state': 'paid'})
except Exception as e:
res['error'] = repr(e)
......
......@@ -16,10 +16,6 @@ function toggle_success_alert() {
$('#envelop_cashing_success').toggle(250);
}
function toggle_deleted_alert() {
$('#envelop_deletion_success').toggle(250);
}
// Set an envelop content on the document
function set_envelop_dom(envelop, envelop_name, envelop_content_id, envelop_index) {
var envelops_section = $('#' + envelop.type + '_envelops');
......@@ -43,7 +39,7 @@ function set_envelop_dom(envelop, envelop_name, envelop_content_id, envelop_inde
}
new_html += '</div>'
+ '<div class="panel panel_' + envelop_content_id + '"><ol id="' + envelop_content_id + '"></ol></div>'
+ '<div class="panel"><ol id="' + envelop_content_id + '"></ol></div>'
+ '</div>';
$(new_html).appendTo(envelops_section);
......@@ -62,9 +58,6 @@ function set_envelop_dom(envelop, envelop_name, envelop_content_id, envelop_inde
li_node.appendChild(textnode); // Append the text to <li>
document.getElementById(envelop_content_id).appendChild(li_node);
}
let envelop_panel = $(`.panel_${envelop_content_id}`);
envelop_panel.append('<button class="btn--danger delete_envelop_button item-fluid" onClick="openModal(\'<h3>Supprimer enveloppe ?</h3>\', function() {delete_envelop(\'' + envelop.type + '\', ' + envelop_index + ');}, \'Supprimer\')">Supprimer l\'enveloppe</button>');
}
// Set the envelops data according to their type
......@@ -125,94 +118,67 @@ function set_envelops(envelops) {
}
}
function delete_envelop(type, index) {
if (is_time_to('delete_envelop', 1000)) {
openModal();
var envelop = null;
if (type == "cash") {
envelop = cash_envelops[index];
} else {
envelop = ch_envelops[index];
}
envelop._deleted = true;
dbc.put(envelop, function callback(err, result) {
if (!err && result !== undefined) {
toggle_deleted_alert();
get_envelops();
} else {
alert("Erreur lors de la suppression de l'enveloppe... Essaye de recharger la page et réessaye.");
console.log(err);
}
});
function archive_envelop(type, index) {
$('#envelop_cashing_error').hide();
$('#envelop_cashing_success').hide();
// Loading on
openModal();
if (type == "cash") {
envelop = cash_envelops[index];
} else {
envelop = ch_envelops[index];
}
}
function archive_envelop(type, index) {
if (is_time_to('archive_envelop', 1000)) {
$('#envelop_cashing_error').hide();
$('#envelop_cashing_success').hide();
// Loading on
openModal();
if (type == "cash") {
envelop = cash_envelops[index];
} else {
envelop = ch_envelops[index];
}
// Proceed to envelop cashing
$.ajax({
type: "POST",
url: "/envelops/archive_envelop",
headers: { "X-CSRFToken": getCookie("csrftoken") },
dataType: "json",
traditional: true,
contentType: "application/json; charset=utf-8",
data: JSON.stringify(envelop),
success: function(response) {
closeModal();
var display_success_alert = true;
// Handle errors when saving payments
var error_payments = response.error_payments;
var error_message = "";
for (var i = 0; i < error_payments.length; i++) {
if (error_payments[i].done == false) {
error_message += "<p>Erreur lors de l'enregistrement du paiement de <b>" + error_payments[i]['partner_name']
+ "</b> (id odoo : " + error_payments[i]['partner_id'] + ", valeur à encaisser : " + error_payments[i]['amount'] + "€).";
error_message += "<br/><b>L'opération est à reprendre manuellement dans Odoo pour ce paiement.</b></p>";
}
// Proceed to envelop cashing
$.ajax({
type: "POST",
url: "/envelops/archive_envelop",
headers: { "X-CSRFToken": getCookie("csrftoken") },
dataType: "json",
traditional: true,
contentType: "application/json; charset=utf-8",
data: JSON.stringify(envelop),
success: function(response) {
closeModal();
var display_success_alert = true;
// Handle errors when saving payments
var error_payments = response.error_payments;
var error_message = "";
for (var i = 0; i < error_payments.length; i++) {
if (error_payments[i].done == false) {
error_message += "<p>Erreur lors de l'enregistrement du paiement de <b>" + error_payments[i]['partner_name']
+ "</b> (id odoo : " + error_payments[i]['partner_id'] + ", valeur à encaisser : " + error_payments[i]['amount'] + "€).";
error_message += "<br/><b>L'opération est à reprendre manuellement dans Odoo pour ce paiement.</b></p>";
}
}
// If error during envelop deletion
var response_envelop = response.envelop;
// If error during envelop deletion
var response_envelop = response.envelop;
if (response_envelop == "error") {
error_message += "<p>Erreur lors de la suppression de l'enveloppe.<br/>";
error_message += "<b>Sauf contre-indication explicite, les paiements ont bien été enregistrés.</b><br/>";
error_message += "Les paiements déjà comptabilisés ne le seront pas à nouveau, vous pouvez ré-essayer. Si l'erreur persiste, l'enveloppe devra être supprimée manuellement.</p>";
display_success_alert = false;
}
if (response_envelop == "error") {
error_message += "<p>Erreur lors de la suppression de l'enveloppe.<br/>";
error_message += "<b>Sauf contre-indication explicite, les paiements ont bien été enregistrés.</b><br/>";
error_message += "Les paiements déjà comptabilisés ne le seront pas à nouveau, vous pouvez ré-essayer. Si l'erreur persiste, l'enveloppe devra être supprimée manuellement.</p>";
display_success_alert = false;
}
if (error_message !== "") {
$('#error_alert_txt').html(error_message);
toggle_error_alert();
}
if (error_message !== "") {
$('#error_alert_txt').html(error_message);
toggle_error_alert();
}
if (display_success_alert) {
toggle_success_alert();
}
},
error: function() {
closeModal();
alert('Erreur serveur. Merci de ne pas ré-encaisser l\'enveloppe qui a causé l\'erreur.');
if (display_success_alert) {
toggle_success_alert();
}
});
}
},
error: function() {
closeModal();
alert('Erreur serveur. Merci de ne pas ré-encaisser l\'enveloppe qui a causé l\'erreur.');
}
});
}
// Get all the envelops from couch db
......
......@@ -15,113 +15,6 @@ default_msettings = {'msg_accueil': {'title': 'Message borne accueil',
'type': 'textarea',
'value': ''
},
'shop_opening_hours': {
'title': 'Horaires ouverture magasin',
'type': 'textarea',
'value': '',
'sort_order': 3
},
'abcd_calendar_link': {
'title': 'Lien vers le calendrier ABCD',
'type': 'text',
'value': '',
'class': 'link',
'sort_order': 4
},
'forms_link': {
'title': 'Lien vers la page des formulaires',
'type': 'text',
'value': '',
'class': 'link',
'sort_order': 5
},
'unsuscribe_form_link': {
'title': 'Lien vers le formulaire de ré-inscription',
'type': 'text',
'value': '',
'class': 'link',
'sort_order': 6
},
'request_form_link': {
'title': 'Faire une demande au Bureau Des Membres',
'type': 'text',
'value': '',
'class': 'link',
'sort_order': 7
},
'late_service_form_link': {
'title': 'Retard à mon service ou oubli validation',
'type': 'text',
'value': '',
'class': 'link',
'sort_order': 8
},
'change_template_form_link': {
'title': 'Demande de changement de créneau',
'type': 'text',
'value': '',
'class': 'link',
'sort_order': 9
},
#TODO vérifier le nom d'un "binome"
'associated_subscribe_form_link': {
'title': 'Demande de création de binôme',
'type': 'text',
'value': '',
'class': 'link',
'sort_order': 10
},
#TODO vérifier le nom d'un "binome"
'associated_unsubscribe_form_link': {
'title': 'Se désolidariser de son binôme',
'type': 'text',
'value': '',
'class': 'link',
'sort_order': 11
},
'template_unsubscribe_form_link': {
'title': 'Se désinscrire de son créneau',
'type': 'text',
'value': '',
'class': 'link',
'sort_order': 12
},
'change_email_form_link': {
'title': 'Changer d\'adresse mail',
'type': 'text',
'value': '',
'class': 'link',
'sort_order': 13
},
'coop_unsubscribe_form_link': {
'title': 'Demande de démission de la coopérative et/ou de remboursement de mes parts sociales',
'type': 'text',
'value': '',
'class': 'link',
'sort_order': 14
},
'sick_leave_form_link': {
'title': 'Demande de congé maladie ou parental',
'type': 'text',
'value': '',
'class': 'link',
'sort_order': 15
},
'underage_subscribe_form_link': {
'title': 'Demande de création d’un compte mineur rattaché',
'type': 'text',
'value': '',
'class': 'link',
'sort_order': 16
},
'member_cant_have_delay_form_link': {
'title': 'Lien vers le formulaire pour les membres n\'ayant pas rattrapé leur service après 6 mois',
'type': 'text',
'value': '',
'class': 'link',
'sort_order': 21
}
}
def config(request):
......
{"msg_accueil": {"title": "Message borne accueil", "type": "textarea", "value": "", "sort_order": 1}, "no_picture_member_advice": {"title": "Message avertissement membre sans photo", "type": "textarea", "value": "", "sort_order": 2}, "shop_opening_hours": {"title": "Horaires ouverture magasin", "type": "textarea", "value": "", "sort_order": 3}, "abcd_calendar_link": {"title": "Lien vers le calendrier ABCD", "type": "text", "value": "", "class": "link", "sort_order": 4}, "forms_link": {"title": "Lien vers la page des formulaires", "type": "text", "value": "", "class": "link", "sort_order": 5}, "unsuscribe_form_link": {"title": "Lien vers le formulaire de r\u00e9-inscription", "type": "text", "value": "https://redmine.cooperatic.fr", "class": "link", "sort_order": 6}, "request_form_link": {"title": "Faire une demande au Bureau Des Membres", "type": "text", "value": "g", "class": "link", "sort_order": 7}, "late_service_form_link": {"title": "Retard \u00e0 mon service ou oubli validation", "type": "text", "value": "f", "class": "link", "sort_order": 8}, "change_template_form_link": {"title": "Demande de changement de cr\u00e9neau", "type": "text", "value": "d", "class": "link", "sort_order": 9}, "associated_subscribe_form_link": {"title": "Demande de cr\u00e9ation de bin\u00f4me", "type": "text", "value": "s", "class": "link", "sort_order": 10}, "associated_unsubscribe_form_link": {"title": "Se d\u00e9solidariser de son bin\u00f4me", "type": "text", "value": "q", "class": "link", "sort_order": 11}, "template_unsubscribe_form_link": {"title": "Se d\u00e9sinscrire de son cr\u00e9neau", "type": "text", "value": "p", "class": "link", "sort_order": 12}, "change_email_form_link": {"title": "Changer d'adresse mail", "type": "text", "value": "o", "class": "link", "sort_order": 13}, "coop_unsubscribe_form_link": {"title": "Demande de d\u00e9mission de la coop\u00e9rative et/ou de remboursement de mes parts sociales", "type": "text", "value": "i", "class": "link", "sort_order": 14}, "sick_leave_form_link": {"title": "Demande de cong\u00e9 maladie ou parental", "type": "text", "value": "u", "class": "link", "sort_order": 15}, "underage_subscribe_form_link": {"title": "Demande de cr\u00e9ation d\u2019un compte mineur rattach\u00e9", "type": "text", "value": "y", "class": "link", "sort_order": 16}, "helper_subscribe_form_link": {"title": "Rejoindre la Brigade Solidaire", "type": "text", "value": "t", "class": "link", "sort_order": 17}, "helper_unsubscribe_form_link": {"title": "Se d\u00e9sinscrire de la brigade solidaire", "type": "text", "value": "r", "class": "link", "sort_order": 18}, "covid_form_link": {"title": "J'ai le Covid-19 !", "type": "text", "value": "e", "class": "link", "sort_order": 19}, "covid_end_form_link": {"title": "Fin d'exemption: reprise de mes services", "type": "text", "value": "z", "class": "link", "sort_order": 20}, "member_cant_have_delay_form_link": {"title": "Lien vers le formulaire pour les membres n'ayant pas rattrap\u00e9 leur service apr\u00e8s 6 mois", "type": "text", "value": "a", "class": "link", "sort_order": 21}}
\ No newline at end of file
......@@ -63,7 +63,6 @@ var html_elts = {
real_capture : $('#real_capture'),
multi_results : $('#multi_results_preview'),
cooperative_state : $('#cooperative_state'),
status_explanation: $('#status_explanation'),
next_shifts : $('#next_shifts')
};
......@@ -93,12 +92,8 @@ function fill_member_slide(member) {
}
html_elts.image_medium.html('<img src="'+img_src+'" width="128" />');
html_elts.cooperative_state.html(member.cooperative_state);
if (member.cooperative_state == 'Rattrapage') {
var explanation = "Tu as dû manquer un service! Pour pouvoir faire tes courses aujourd'hui, tu dois d'abord sélectionner un rattrapage sur ton espace membre."
html_elts.status_explanation.html(explanation)
}
if (member.cooperative_state == 'Désinscrit(e)') coop_info.addClass('b_red');
else if (member.cooperative_state == 'En alerte' || member.cooperative_state == 'Délai accordé' || member.cooperative_state == 'Rattrapage') coop_info.addClass('b_orange');
else if (member.cooperative_state == 'En alerte' || member.cooperative_state == 'Délai accordé') coop_info.addClass('b_orange');
if (member.shifts.length > 0) {
html_elts.next_shifts.append('Prochains services : ');
......
......@@ -96,7 +96,14 @@ function process_form_submission(event) {
closeModal();
if (!err) {
window.location.href = em_url;
var msg = "Vous êtes maintenant enregistré ! ";
msg += "<a href='" + em_url + "'>Cliquez ici</a> ";
msg += "pour découvrir l'espace membre";
$('p.intro').remove();
vform.remove();
display_msg_box(msg);
}
}
......
from django.db import models
from outils.common_imports import *
from members.models import CagetteServices
from outils.common import OdooAPI
class CagetteMembersSpace(models.Model):
"""Class to manage othe members space"""
def __init__(self):
"""Init with odoo id."""
self.o_api = OdooAPI()
def is_comite(self, partner_id):
"""Check if partner is from comite."""
cond = [['partner_id.id', '=', partner_id]]
fields = ['shift_template_id', 'is_current']
shiftTemplate = self.o_api.search_read('shift.template.registration', cond, fields)
answer = False
if (shiftTemplate and len(shiftTemplate) > 0):
s_t_id = None
for s_t in shiftTemplate:
if s_t['is_current'] is True:
s_t_id = s_t['shift_template_id'][0]
if s_t_id == CagetteServices.get_committees_shift_id():
answer = True
return answer
def get_shifts_history(self, partner_id, limit, offset, date_from):
""" Get partner shifts history """
res = []
paginated_res = []
today = str(datetime.date.today())
try:
cond = [
['partner_id', '=', partner_id],
['date_begin', '>', date_from],
['date_begin', '<', today],
['state', '!=', 'draft'],
['state', '!=', 'open'],
['state', '!=', 'waiting'],
['state', '!=', 'replaced'],
['state', '!=', 'replacing'],
]
f = ['create_date', 'date_begin', 'shift_id', 'name', 'state', 'is_late', 'is_makeup']
marshal_none_error = 'cannot marshal None unless allow_none is enabled'
try:
res = self.o_api.search_read('shift.registration', cond, f, order='date_begin DESC')
except Exception as e:
if not (marshal_none_error in str(e)):
print(str(e))
coop_logger.error(repr(e) + ' : %s', str(partner_id))
else:
res = []
# Get committees shifts
committees_shifts_name = getattr(settings, 'ENTRANCE_ADD_PT_EVENT_NAME', 'Validation service comité')
cond = [
['partner_id', '=', partner_id],
['name', '=', committees_shifts_name]
]
f = ['create_date']
try:
res_committees_shifts = self.o_api.search_read('shift.counter.event', cond, f, order='create_date DESC')
for committee_shift in res_committees_shifts:
item = {
"create_date": committee_shift["create_date"],
"date_begin": committee_shift["create_date"],
"shift_id": False,
"name": "Services des comités",
"state": "done",
"is_late": False,
"is_makeup": False,
}
res.append(item)
except Exception as e:
if not (marshal_none_error in str(e)):
print(str(e))
coop_logger.error(repr(e) + ' : %s', str(partner_id))
else:
res = res + []
# Add amnesty line
is_amnesty = getattr(settings, 'AMNISTIE_DATE', False)
company_code = getattr(settings, 'COMPANY_CODE', '')
if is_amnesty and company_code == "lacagette":
amnesty = {}
amnesty['is_amnesty'] = True
amnesty['create_date'] = is_amnesty
amnesty['date_begin'] = is_amnesty
amnesty['shift_name'] = 'Amnistie'
amnesty['state'] = ''
res.append(amnesty)
# Ordering here is necessary for pagination
res.sort(key = lambda x: datetime.datetime.strptime(x['date_begin'], '%Y-%m-%d %H:%M:%S'), reverse=True)
# Paginate
end_index = offset + limit
paginated_res = res[offset:end_index]
except Exception as e:
coop_logger.error("get_shifts_history : %s", str(e))
return paginated_res
\ No newline at end of file
/* Add a black background color to the top navigation */
.topnav {
background-color: white;
overflow: hidden;
border-bottom: 1px solid #e7e9ed;
}
/* Style the links inside the navigation bar */
.topnav a {
float: left;
display: block;
color: #333;
text-align: center;
padding: 2rem 1.5rem;
text-decoration: none;
font-size: 17px;
font-weight: bold;
}
/* Change the color of links on hover */
.topnav a:hover {
background-color: #e7e9ed;
color: #333;
}
/* Add an active class to highlight the current page */
.topnav a.active {
background-color: #00a573;
color: white;
}
/* Hide the link that should open and close the topnav on small screens */
.topnav .icon {
display: none;
}
.pairs_info {
background-color: #00a573;
color: white;
padding: 1.5rem 1.2rem;
display: none;
}
@media screen and (max-width: 1146px) {
/* When the screen is less than 1146px pixels wide, hide all links, except for the first one ("Home"). Show the link that contains should open and close the topnav (.icon) */
.topnav a:not(:first-child) {display: none;}
.topnav a.icon {
float: right;
display: block;
}
/* The "responsive" class is added to the topnav with JavaScript when the user clicks on the icon. This class makes the topnav look good on small screens (display the links vertically instead of horizontally) */
.topnav.responsive {position: relative;}
.topnav.responsive a.icon {
position: absolute;
right: 0;
top: 0;
}
.topnav.responsive a {
float: none;
display: block;
text-align: left;
}
#deconnect {
float: none;
}
}
/* We override some styles defined on the home page for the specific needs of the My Info page */
#my_info {
font-size: 2rem;
}
#my_info_content {
display: flex;
flex-direction: column;
margin: 2rem 0;
}
.my_info_line {
display: flex;
flex-wrap: wrap;
width: 100%;
padding: 1.5rem 0;
}
@media screen and (min-width: 351px) and (max-width: 435px) {
.my_info_line {
font-size: 90%;
padding: 2vw 0;
}
}
@media screen and (max-width: 350px) {
.my_info_line {
font-size: 3.5vw;
padding: 2vw 0;
}
}
.my_info_line_left {
width: 50%;
text-align: right;
padding-right: 2rem;
font-weight: bold;
}
.my_info_line_right {
width: 50%;
padding-left: 2rem;
max-width: 100%;
word-break: break-all;
}
.my_info_line_middle {
width: 70%;
max-width: 100%;
word-break: normal;
text-align: center;
margin: 3rem 0;
}
#my_info #member_status_action,
#my_info .member_shift_name_area,
#my_info .member_coop_number_area {
margin-bottom: 0;
}
#my_info .member_shift_name_area {
margin-top: 0;
}
#attached_info {
display: flex;
flex-direction: column;
}
.member_phone_area {
display: flex;
flex-direction: column;
gap: 10px;
}
.edit-btn{
cursor: pointer;
}
#edit_address_form {
display: none ;
}
#edit_address_form #zip_form {
margin: 5px 0;
}
#edit_phone_form {
display: none ;
}
#edit_phone_form #mobile_form {
margin: 5px 0;
}
@media screen and (max-width: 992px) {
#my_info {
font-size: 1.7rem;
}
.my_info_line_left {
width: 30%;
padding-right: 1rem;
}
.my_info_line_right {
width: 70%;
padding-left: 1rem;
}
#attached_info .my_info_line_left {
width: 100%;
text-align: left;
padding: 0;
}
#attached_info .my_info_line_right {
width: 100%;
padding: 0;
}
#my_info .choose_makeups,
#my_info .unsuscribed_form_link {
white-space: normal;
}
#my_info .delay_date_stop_container {
white-space: nowrap;
}
#my_info .member_coop_number_area,
#my_info .member_shift_name_area {
align-items: flex-start;
}
}
.status_info_image {
display: block;
margin: 5rem auto 5rem auto;
width: 50%;
}
#my_shifts {
font-size: 1.8rem;
}
#incoming_shifts {
height: 100%;
flex-direction: column;
display: none;
}
.loading-history, .loading-incoming-shifts {
margin: 2rem 0;
}
#history {
display: flex;
flex-direction: column;
display: none;
}
table.dataTable tbody td {
text-overflow: ellipsis;
}
table.dataTable thead .sorting,
table.dataTable thead .sorting_asc,
table.dataTable thead .sorting_desc {
background : none;
}
table.dataTable.dtr-inline.collapsed>tbody>tr>td:first-child:before,
table.dataTable.dtr-inline.collapsed>tbody>tr>th:first-child:before {
color: #0275d8;
background-color: white;
font-weight: bold;
/* border: none;
font-size: 1.6rem;
height: 16px;
width: 16px;
border-radius: 2em; */
}
@media screen {
}
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td:first-child:before,
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th:first-child:before {
color: #d8534f;
background-color: white;
font-weight: bold;
/* border: none;
font-size: 1.6rem;
height: 16px;
width: 16px;
border-radius: 2em; */
}
.loading-more-history {
display: none;
}
.more_history {
display: flex;
justify-content: center;
align-items: center;
margin-top: 20px;
font-size: 2rem;
}
.more_history_button {
height: 50px;
width: 50px;
border-radius: 50%;
}
table.dataTable.display tbody tr.row_partner_ok {
background-color: #8feb8b;
}
table.dataTable.display tbody tr.row_partner_late {
background-color: #ffdf7d;
}
table.dataTable.display tbody tr.row_partner_absent {
background-color: #ff847b;
}
table.dataTable.display tbody tr.row_partner_amnistie {
background-color: rgb(78, 78, 78);
color: white;
}
table.dataTable.display tbody tr td {
border-top: 1px solid rgb(119, 119, 119);
}
\ No newline at end of file
.shifts_exchange_page_content {
width: 95%;
margin: 3rem auto;
display: flex;
flex-direction: column;
position: relative;
}
/* -- Suspended screen */
#suspended_content, #unsuscribed_content {
align-items: center;
text-align: center;
}
#shifts_exchange .select_makeups, #shifts_exchange .unsuscribed_form_link, .cant_have_delay_form_link {
margin: 1.5rem 0;
}
/* -- Suspended can't have delay screen */
#suspended_cant_have_delay_content {
align-items: center;
text-align: center;
width: 50%;
}
@media screen and (max-width:992px) {
#suspended_cant_have_delay_content {
align-items: center;
text-align: center;
width: 90%;
}
}
/* -- Calendar screen, area on top of the calendar */
#calendar_top_info {
display: flex;
justify-content: space-between;
}
@media screen and (max-width:992px) {
#calendar_top_info {
display: flex;
flex-direction: column;
justify-content: space-between;
}
}
/* -- Calendar screen, shifts list */
#shifts_list {
flex-direction: column;
display: none;
width: min-content;
max-width: 100%;
white-space: nowrap;
}
@media screen and (max-width:992px) {
#partner_shifts_list {
display: flex;
flex-direction: column;
align-items: center;
}
}
.selectable_shift_line {
display: flex;
align-items: center;
margin-left: 15px;
margin: 0.75rem 0;
border-radius: 5px;
}
.selectable_shift_line .checkbox {
margin-right: 10px;
}
.selectable_shift_line.btn {
cursor: not-allowed;
}
/* -- Calendar screen, makeups message */
#need_to_select_makeups_message {
display: none;
align-self: center;
background-color: #d9534f;
color: white;
margin: 0 1rem 2rem 1rem;
padding: 1rem 1.25rem;
text-align: center;
}
.makeups_warning {
margin-right: 3px;
}
@media screen and (max-width:992px) {
.select_makeups_message_block {
display: block;
}
}
/* -- Calendar screen, calendar */
#calendar {
margin: 2rem 1rem;
}
.loading-calendar {
margin: 3rem auto;
display: none;
}
@media screen and (max-width:992px) {
#calendar {
display: none;
}
}
.fc .fc-event {
cursor: pointer;
margin: 1px 10px !important;
}
.fc-event {
background-color: #008AD9;
border-color: #008AD9;
color: white;
}
td{
--fc-list-event-hover-bg-color:#005BA6;
}
.fc-event.shift_booked {
background-color: #585858;
cursor: auto;
border-color: #585858;
}
.fc-event.shift_booked td {
--fc-list-event-hover-bg-color:#585858;
}
.fc-list-event.shift_booked {
color: white;
}
#calendar .fc-list-table {
table-layout: auto;
}
.resp-header-toolbar {
display: flex;
flex-direction: column;
}
.resp-header-toolbar .fc-toolbar-chunk {
text-align: center;
margin: 0.25rem;
}
.date_old_shift, .time_old_shift, .date_new_shift, .time_new_shift {
font-weight: bold;
}
/* -- Explainations */
#calendar_explaination_area {
max-width: 33%;
border: 2px solid #585858;
border-radius: 15px;
padding: 1rem;
}
.example-event {
max-width: 200px;
margin: 2rem 0 0.5rem 0;
font-size: 1.4rem !important;
padding: 0 !important;
}
@media screen and (max-width:992px) {
.example-event {
margin: 2rem auto 0.5rem auto;
}
}
.arrow_explanation_numbers {
margin: 0 3px;
}
#calendar_explaination_button {
max-width: 60%;
margin: 2rem auto 0.5rem auto;
}
\ No newline at end of file
body {
margin: 0;
}
.page_title {
margin: 35px 0 30px 0;
}
@media screen and (max-width: 435px) {
.page_title {
margin: 4vw 0 3vw 0;
}
}
/* -- Tiles */
.tiles_container {
display: flex;
flex-wrap: wrap;
}
@media screen and (max-width: 992px) {
.tiles_container {
flex-direction: column;
}
}
.tile {
flex: 1 0 45%;
display: flex;
flex-direction: column;
align-items: center;
border-radius: 30px;
margin: 1rem 1rem;
box-shadow: 2px 2px 3px rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.1);
}
.high_tile {
min-height: 350px;
}
.small_tile {
min-height: 250px;
}
.full_width_tile {
flex: 1 0 90%;
min-height: 100px;
}
.tile_title {
display: flex;
justify-content: center;
align-items: center;
border-bottom: 1px solid #e7e9ed;
font-size: 2.4rem;
padding: 2rem 0;
width: 80%;
}
.tile_content {
position: relative;
margin: 3rem 0;
width: 80%;
display: flex;
height: 100%;
}
#home_tile_services_exchange .tile_content {
height: 100%;
flex-direction: column;
align-items: center;
text-align: center;
}
/* -- My Shifts tile */
#home_tile_my_services .tile_content {
height: 100%;
flex-direction: column;
margin: auto;
padding: 2rem 0;
}
@media screen and (min-width: 769px) {
#home_tile_my_services .tile_content {
width: 50%;
}
}
#home_incoming_services {
min-height: 80px;
display: flex;
flex-direction: column;
}
.shift_line {
margin-left: 15px;
line-height: 2;
}
.shift_line_chevron {
color: #D9534F;
margin-right: 5px;
}
#go_to_shift_history_area {
width: 100%;
display: flex;
justify-content: center;
}
#home_go_to_shift_history {
width: 100%;
margin-top: 30px;
}
/* -- My Info tile */
#home_tile_my_info {
position: relative;
}
#home_tile_my_info .tile_content {
margin: 2rem 0;
}
.tile_icon {
margin-right: 15px;
color: #00a573;
}
#home_tile_my_info .tile_content {
height: 100%;
flex-direction: column;
align-items: center;
font-size: 1.6rem;
}
@media screen and (max-width: 576px) {
#home_tile_my_info .tile_content {
font-size: 1.4rem !important;
}
}
#home .member_info {
font-weight: bold;
}
.member_status_text_container {
margin-bottom: 5px;
}
#member_status_action {
display: flex;
margin-bottom: 20px;
}
@media screen and (max-width: 992px) {
#member_status_action {
margin-top: 5px;
margin-bottom: 10px;
}
}
.choose_makeups {
display: none;
font-size: 1.5rem;
}
.unsuscribed_form_link {
display: none;
text-decoration: none;
font-size: 1.7rem;
word-break: normal;
}
.unsuscribed_form_link:hover {
text-decoration: none;
}
@media (max-width: 435px) {
.unsuscribed_form_link {
font-size: 90%;
line-height: 7vw;
}
}
.member_status_up_to_date,
.member_status_exempted {
color: #5cb85c;
}
.member_status_alert,
.member_status_delay {
color: #f0ad4e;
}
.member_status_suspended,
.member_status_unsubscribed {
color: #d9534f;
}
.member_shift_name_area,
.member_coop_number_area {
margin-bottom: 10px;
}
.member_associated_partner_area {
line-height: 1.3;
}
@media screen and (max-width: 992px) {
.member_associated_partner_area {
display: flex;
flex-direction: column;
align-items: center;
}
}
.delay_date_stop_container {
color: #f0ad4e;
margin-top: -1rem;
margin-bottom: 1rem;
display: none;
}
#see_more_info {
white-space: normal;
}
#see_more_info_link {
width: 100%;
}
/* --Shifts exchange tile tile */
.home_link_button_area {
width: 100%;
display: flex;
justify-content: center;
height: 100%;
}
.home_link_button {
width: 80%;
margin: 30px auto auto auto;
white-space: normal;
}
/* -- I have a question tile */
#go_to_forms {
text-decoration: none;
}
#go_to_forms:hover {
color: white;
}
#go_to_forms.active {
color: white !important;
}
/* -- Shop info tile */
#shop_info_content {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
width: 80%;
margin: auto;
}
.shop_info_item {
width: 50%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 2rem;
flex: 1 0 50%;
}
.shop_info_item h1,h2,h3,h4,h5,h6 {
font-size: 2rem;
}
.opening_hours_title {
margin-bottom: 10px;
font-size: 2.3rem;
font-weight: bold;
}
.shop_message_content {
text-align: center;
}
@media screen and (min-width: 769px) {
.shop_info_item {
padding: 0 4rem;
}
.shop_message {
border-left: 1px solid #e7e9ed;
margin: 3rem 0;
}
}
@media screen and (max-width: 992px) {
#shop_info_content {
flex-direction: column;
}
.shop_info_item {
flex: 1 0 50%;
width: 100%;
font-size: 1.6rem;
padding: 1.5rem 0;
}
.shop_info_item h1,h2,h3,h4,h5,h6 {
font-size: 1.6rem;
}
.opening_hours_title {
font-size: 1.9rem;
}
.shop_message {
border-top: 1px solid #e7e9ed;
}
.shop_message_content {
width: 90%;
}
}
/* - No content page */
.message_error {
padding: 7vw;
font-size: 1.8rem;
}
.no_content_title {
margin-bottom: 1.5rem;
}
function init_faq() {
$("#unsuscribe_form_link_btn").prop("href", unsuscribe_form_link);
$("#unsuscribe_form_link_btn2").prop("href", unsuscribe_form_link);
$("#change_template_form_link_btn").prop("href", change_template_form_link);
$("#template_unsubscribe_form_link_btn").prop("href", template_unsubscribe_form_link);
$("#late_service_form_link_btn").prop("href", late_service_form_link);
$("#sick_leave_form_link_btn").prop("href", sick_leave_form_link);
$("#associated_subscribe_form_link_btn").prop("href", associated_subscribe_form_link);
$("#associated_unsubscribe_form_link_btn").prop("href", associated_unsubscribe_form_link);
$("#covid_form_link_btn").prop("href", covid_form_link);
$("#covid_end_form_link_btn").prop("href", covid_end_form_link);
$("#underage_subscribe_form_link_btn").prop("href", underage_subscribe_form_link);
$("#change_email_form_link_btn").prop("href", change_email_form_link);
$("#coop_unsubscribe_form_link_btn").prop("href", coop_unsubscribe_form_link);
$("#helper_subscribe_form_link_btn").prop("href", helper_subscribe_form_link);
$("#helper_unsubscribe_form_link_btn").prop("href", helper_unsubscribe_form_link);
$("#request_form_link_btn2").prop("href", request_form_link);
$("#request_form_link_btn").prop("href", request_form_link);
}
$(document).on('click', "#shift_exchange_btn", () => {
goto('echange-de-services');
});
\ No newline at end of file
/**
* Request a 6 month delay
*/
function request_delay() {
return new Promise((resolve) => {
let today = new Date();
const delay_start = today.getFullYear()+'-'+(today.getMonth()+1)+'-'+today.getDate();
let today_plus_six_month = new Date();
today_plus_six_month.setMonth(today_plus_six_month.getMonth()+6);
const diff_time = Math.abs(today_plus_six_month - today);
const diff_days = Math.ceil(diff_time / (1000 * 60 * 60 * 24));
$.ajax({
type: 'POST',
url: "/shifts/request_delay",
dataType:"json",
data: {
verif_token: partner_data.verif_token,
idPartner: partner_data.partner_id,
start_date: delay_start,
duration: diff_days
},
success: function() {
partner_data.cooperative_state = 'delay';
partner_data.date_delay_stop = today_plus_six_month.getFullYear()+'-'+(today_plus_six_month.getMonth()+1)+'-'+today_plus_six_month.getDate();
resolve();
},
error: function(data) {
if (data.status == 403
&& typeof data.responseJSON != 'undefined'
&& data.responseJSON.message === "delays limit reached") {
closeModal();
let msg_template = $("#cant_have_delay_msg_template");
openModal(
msg_template.html(),
() => {
window.location =member_cant_have_delay_form_link;
},
"J'accède au formulaire",
true,
false
);
} else {
err = {msg: "erreur serveur lors de la création du délai", ctx: 'request_delay'};
if (typeof data.responseJSON != 'undefined' && typeof data.responseJSON.error != 'undefined') {
err.msg += ' : ' + data.responseJSON.error;
}
report_JS_error(err, 'members_space.home');
closeModal();
alert('Erreur lors de la création du délai.');
}
}
});
});
}
function init_my_shifts_tile() {
if (incoming_shifts.length === 0) {
$("#home_tile_my_services #home_incoming_services").text("Aucun service à venir...");
} else {
$("#home_tile_my_services #home_incoming_services").empty();
let cpt = 0;
for (shift of incoming_shifts) {
if (cpt === 3) {
break;
} else {
let shift_line_template = prepare_shift_line_template(shift.date_begin);
$("#home_tile_my_services #home_incoming_services").append(shift_line_template.html());
cpt++;
}
}
}
}
function init_home() {
$("#go_to_shifts_calendar").on("click", () => {
goto('echange-de-services');
});
$("#home_go_to_shift_history").on("click", () => {
goto('mes-services');
});
$("#see_more_info_link").on('click', (e) => {
e.preventDefault();
goto('mes-infos');
});
// $("#go_to_forms").prop("href", "forms_link");
$("#go_to_forms").on('click', (e) => {
e.preventDefault();
goto('faq');
});
if (partner_data.is_in_association === false) {
$("#home .member_associated_partner_area").hide();
} else {
if (partner_data.is_associated_people === "True") {
$(".member_associated_partner").text(partner_data.parent_name);
} else if (partner_data.associated_partner_id !== "False") {
$(".member_associated_partner").text(partner_data.associated_partner_name);
}
}
// TODO vérif tile my info avec données binomes + rattrapage et délai
// Init my info tile
init_my_info_data();
if (incoming_shifts !== null) {
init_my_shifts_tile();
} else {
load_partner_shifts(partner_data.concerned_partner_id)
.then(init_my_shifts_tile);
}
}
\ No newline at end of file
var history_table = null;
const history_items_limit = 10;
/**
* Load the partner points history
*/
function load_partner_history(offset = 0) {
return new Promise((resolve) => {
$.ajax({
type: 'GET',
url: "/members_space/get_shifts_history",
data: {
partner_id: partner_data.concerned_partner_id,
verif_token: partner_data.verif_token,
limit: history_items_limit,
offset: offset
},
dataType:"json",
traditional: true,
contentType: "application/json; charset=utf-8",
success: function(data) {
formatted_data = prepare_server_data(data.data);
resolve(formatted_data);
},
error: function(data) {
err = {msg: "erreur serveur lors de la récupération de l'historique", ctx: 'load_partner_history'};
if (typeof data.responseJSON != 'undefined' && typeof data.responseJSON.error != 'undefined') {
err.msg += ' : ' + data.responseJSON.error;
}
report_JS_error(err, 'members_space.my_shifts');
closeModal();
// TODO Notify
alert('Erreur lors de la récupération de votre historique.');
}
});
});
}
/**
* Format history data to insert in the table
*
* @param {Array} data
* @returns formated data array
*/
function prepare_server_data(data) {
res = [];
for (history_item of data) {
if (history_item.is_amnesty !== undefined) {
let shift_datetime = new Date(history_item.date_begin);
let str_shift_datetime = `${("0" + shift_datetime.getDate()).slice(-2)}/${("0" + (shift_datetime.getMonth() + 1)).slice(-2)}/${shift_datetime.getFullYear()}`;
history_item.shift_name = `${history_item.shift_name} du ${str_shift_datetime}`;
} else {
history_item.shift_name = (history_item.shift_id === false) ? '' : history_item.shift_id[1];
if (history_item.name === "Services des comités") {
let shift_datetime = new Date(history_item.date_begin);
let str_shift_datetime = `${("0" + shift_datetime.getDate()).slice(-2)}/${("0" + (shift_datetime.getMonth() + 1)).slice(-2)}/${shift_datetime.getFullYear()}`;
str_shift_datetime = str_shift_datetime + " " + shift_datetime.toLocaleTimeString("fr-fr", time_options);
history_item.shift_name = `Services des comités ${str_shift_datetime}`;
}
}
history_item.details = '';
if (history_item.state === 'excused' || history_item.state === 'absent') {
history_item.details = "Absent.e";
} else if (history_item.state === 'done' && history_item.is_late != false) {
history_item.details = "Présent.e (En Retard)";
} else if (history_item.state === 'done') {
history_item.details = "Présent.e";
} else if (history_item.state === 'cancel') {
history_item.details = "Annulé";
}
}
return data;
}
/**
* Init the History section: display the history table
*/
function init_history() {
$(".loading-history").hide();
$("#history").show();
if (partner_history.length === 0) {
$("#history").empty()
.text("Aucun historique... pour l'instant !");
} else {
history_table = $('#history_table').DataTable({
data: partner_history,
columns: [
{
data: "date_begin",
title: "",
visible: false
},
{
data: "shift_name",
title: "<spans class='dt-body-center'>Service</span>",
width: "60%",
orderable: false
},
{
data: "details",
title: "Détails",
className: "tablet-l desktop",
orderable: false
}
],
iDisplayLength: -1,
order: [
[
0,
"desc"
]
],
language: {url : '/static/js/datatables/french.json'},
dom: "t",
responsive: true,
createdRow: function(row) {
for (var i = 0; i < row.cells.length; i++) {
const cell = $(row.cells[i]);
if (cell.text() === "Présent.e") {
$(row).addClass('row_partner_ok');
} else if (cell.text() === "Retard") {
$(row).addClass('row_partner_late');
} else if (cell.text() === "Absent.e") {
$(row).addClass('row_partner_absent');
} else if (cell.text().includes("Amnistie")) {
$(row).addClass('row_partner_amnistie');
}
}
}
});
}
}
/**
* Init the Incoming shifts section: display them
*/
function init_incoming_shifts() {
$(".loading-incoming-shifts").hide();
$("#incoming_shifts").show();
if (incoming_shifts.length === 0) {
$("#incoming_shifts").text("Aucun service à venir...");
} else {
$("#incoming_shifts").empty();
for (shift of incoming_shifts) {
let shift_line_template = prepare_shift_line_template(shift.date_begin);
$("#incoming_shifts").append(shift_line_template.html());
}
}
}
function init_my_shifts() {
if (incoming_shifts !== null) {
init_incoming_shifts();
} else {
load_partner_shifts(partner_data.concerned_partner_id)
.then(init_incoming_shifts);
}
if (partner_history !== null) {
init_history();
} else {
load_partner_history()
.then((data) => {
partner_history = data;
for (d of data) {
d.create_date = Date.parse(d.create_date);
}
// Sort by date desc
partner_history.sort((a, b) => b.create_date - a.create_date);
if (partner_history.length>0 && partner_history[partner_history.length-1].is_amnesty != undefined) {
partner_history.pop();
}
init_history();
});
}
$(".more_history_button").on("click", function() {
// Hide button & display loading
$('.more_history_button').hide();
$('.loading-more-history').show();
load_partner_history(partner_history.length)
.then((data) => {
partner_history = partner_history.concat(data);
if (history_table) {
history_table.rows.add(data).draw(false);
}
$('.loading-more-history').hide();
// Show "load more" if there is more to load
if (data.length === history_items_limit) {
$('.more_history_button').show();
}
});
});
}
/**
* Common logic between pages
*/
var base_location = null,
current_location = null,
incoming_shifts = null,
partner_history = null;
var date_options = {weekday: "long", year: "numeric", month: "long", day: "numeric"};
var time_options = {hour: '2-digit', minute:'2-digit'};
const possible_cooperative_state = {
suspended: "Rattrapage",
exempted: "Exempté.e",
alert: "En alerte",
up_to_date: "À jour",
unsubscribed: "Désinscrit.e des créneaux",
delay: "En délai",
gone: "Parti.e"
};
/* - Data */
/**
* Load the shifts the member is registered to
* @param {int} partner_id either the members id, or its parent's if s.he's attached
*/
function load_partner_shifts(partner_id) {
return new Promise((resolve) => {
$.ajax({
type: 'GET',
url: "/shifts/get_list_shift_partner/" + partner_id,
dataType:"json",
traditional: true,
contentType: "application/json; charset=utf-8",
success: function(data) {
incoming_shifts = data;
resolve();
},
error: function(data) {
err = {msg: "erreur serveur lors de la récupération des services", ctx: 'load_partner_shifts'};
if (typeof data.responseJSON != 'undefined' && typeof data.responseJSON.error != 'undefined') {
err.msg += ' : ' + data.responseJSON.error;
}
report_JS_error(err, 'members_space.index');
closeModal();
// TODO Notify
alert('Erreur lors de la récupération de vos services.');
}
});
});
}
/* - Navigation */
/**
* @param {String} page home | mes-infos | mes-services | echange-de-services | faq
*/
function goto(page) {
if (window.location.pathname === base_location) {
history.pushState({}, '', page);
} else {
history.replaceState({}, '', page);
}
update_dom();
}
/**
* Define which html content to load from server depending on the window location
*
* WARNING: For the routing system to work,
* public urls (those the users will see & navigate to) must be different than the server urls used to fetch resources
* (ex: public url: /members_space/mes-info ; server url: /members_space/my_info)
*/
function update_dom() {
$(".nav_item").removeClass('active');
if (window.location.pathname === base_location || window.location.pathname === base_location + "home") {
current_location = "home";
$("#main_content").load("/members_space/homepage", update_content);
$("#nav_home").addClass("active");
} else if (window.location.pathname === base_location + "mes-infos") {
current_location = "my_info";
$("#main_content").load("/members_space/my_info", update_content);
$("#nav_my_info").addClass("active");
} else if (window.location.pathname === base_location + "mes-services") {
current_location = "my_shifts";
$("#main_content").load("/members_space/my_shifts", update_content);
$("#nav_my_shifts").addClass("active");
} else if (window.location.pathname === base_location + "faq") {
current_location = "faq";
$("#main_content").load("/members_space/faqBDM", update_content);
$("#nav_faq").addClass("active");
} else if (window.location.pathname === base_location + "echange-de-services") {
current_location = "shifts_exchange";
$("#main_content").load("/members_space/shifts_exchange", update_content);
$("#nav_shifts_exchange").addClass("active");
} else {
$("#main_content").load("/members_space/no_content");
}
}
/**
* Update the data displayed depending on the current location
* (ex: insert personal data in the DOM when on the 'My Info' page)
*/
function update_content() {
switch (current_location) {
case 'home':
init_home();
break;
case 'my_info':
init_my_info();
break;
case 'my_shifts':
init_my_shifts();
break;
case 'faq':
init_faq();
break;
case 'shifts_exchange':
init_shifts_exchange();
break;
default:
console.log(`Bad input`);
}
}
/* - Shifts */
/**
* Prepare a shift line to insert into the DOM.
* Is used in: Home - My Shifts tile ; My Shifts - Incoming shifts section
*
* @param {String} date_begin beginning datetime of the shift
* @returns JQuery node object of the formatted template
*/
function prepare_shift_line_template(date_begin) {
let shift_line_template = $("#shift_line_template");
let datetime_shift_start = new Date(date_begin.replace(/\s/, 'T'));
let f_date_shift_start = datetime_shift_start.toLocaleDateString("fr-fr", date_options);
f_date_shift_start = f_date_shift_start.charAt(0).toUpperCase() + f_date_shift_start.slice(1);
shift_line_template.find(".shift_line_date").text(f_date_shift_start);
shift_line_template.find(".shift_line_time").text(datetime_shift_start.toLocaleTimeString("fr-fr", time_options));
return shift_line_template;
}
/* - Member info */
/**
* Init common personal data between screens
*/
function init_my_info_data() {
$(".choose_makeups").off();
$(".unsuscribed_form_link").off();
$(".member_shift_name").text(partner_data.regular_shift_name);
let pns = partner_data.name.split(" - ");
let name = pns.length > 1 ? pns[1] : pns[0];
$(".member_name").text(name);
// Status related
$(".member_status")
.text(possible_cooperative_state[partner_data.cooperative_state])
.addClass("member_status_" + partner_data.cooperative_state);
if (partner_data.cooperative_state === 'delay' && partner_data.date_delay_stop !== 'False') {
const d = new Date(Date.parse(partner_data.date_delay_stop));
const f_date_delay_stop = d.getDate()+'/'+("0" + (d.getMonth() + 1)).slice(-2)+'/'+d.getFullYear();
$(".delay_date_stop").text(f_date_delay_stop);
$(".delay_date_stop_container").show();
} else if (partner_data.cooperative_state === 'unsubscribed' || partner_data.cooperative_state === 'gone') {
$(".member_shift_name").text('X');
$(".unsuscribed_form_link")
.show()
.attr('href', unsuscribe_form_link)
.on('click', function() {
setTimeout(500, () => {
$(this).removeClass('active');
});
});
} else if (partner_data.cooperative_state === 'exempted') {
const d = new Date(Date.parse(partner_data.leave_stop_date));
const f_date_delay_stop = d.getDate()+'/'+("0" + (d.getMonth() + 1)).slice(-2)+'/'+d.getFullYear();
$(".delay_date_stop").text(f_date_delay_stop);
$(".delay_date_stop_container").show();
}
if (
partner_data.makeups_to_do > 0
&& partner_data.is_associated_people === "False"
&& partner_data.cooperative_state !== 'unsubscribed'
) {
$(".choose_makeups").show();
if (
partner_data.cooperative_state === 'suspended'
&& partner_data.date_delay_stop === 'False') {
// If the member is suspended & doesn't have a delay
$(".choose_makeups").on('click', () => {
// Create 6 month delay
request_delay()
.then(() => {
// Then redirect to calendar
goto('echange-de-services');
});
});
} else {
$(".choose_makeups").on('click', () => {
goto('echange-de-services');
});
}
}
$(".member_coop_number").text(partner_data.barcode_base);
}
$(document).ready(function() {
// TODO essayer de ne charger les js que au besoin
$.ajaxSetup({ headers: { "X-CSRFToken": getCookie('csrftoken') } });
// If partner is associated (attached), display the pair's main partner shift data
partner_data.concerned_partner_id =
(partner_data.is_associated_people === "True")
? partner_data.parent_id
: partner_data.partner_id;
partner_data.is_in_association =
partner_data.is_associated_people === "True" || partner_data.associated_partner_id !== "False";
// For associated people, their parent name is attached in their display name
let partner_name_split = partner_data.name.split(', ');
partner_data.name = partner_name_split[partner_name_split.length - 1];
base_location = (app_env === 'dev') ? '/members_space/' : '/';
update_dom();
window.onpopstate = function() {
update_dom();
};
});
(function($, sr) {
// debouncing function from John Hann
// http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
var debounce = function (func, threshold, execAsap) {
var timeout;
return function debounced () {
var obj = this, args = arguments;
function delayed () {
if (!execAsap)
func.apply(obj, args);
timeout = null;
}
if (timeout)
clearTimeout(timeout);
else if (execAsap)
func.apply(obj, args);
timeout = setTimeout(delayed, threshold || 100);
};
};
// smartresize
jQuery.fn[sr] = function(fn) {
return fn ? this.bind('resize', debounce(fn)) : this.trigger(sr);
};
})(jQuery, 'smartresize');
\ No newline at end of file
"""."""
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index),
url(r'^homepage$', views.home), # These endpoints must be different than in-app url
url(r'^my_info$', views.my_info),
url(r'^my_shifts$', views.my_shifts),
url(r'^shifts_exchange$', views.shifts_exchange),
url(r'^faqBDM$', views.faqBDM),
url(r'^no_content$', views.no_content),
url(r'^get_shifts_history$', views.get_shifts_history),
url(r'^.*', views.index) # Urls unknown from the server will redirect to index
]
......@@ -82,48 +82,6 @@
justify-content: flex-start;
}
.right_action_buttons {
display: flex;
}
#actions_buttons_wrapper {
position: relative;
margin-right: 5px;
}
#toggle_action_buttons {
width: 250px;
position: relative;
}
.toggle_action_buttons_icon {
position: absolute;
top: 50%;
transform: translateY(-50%);
right: 15px;
}
#actions_buttons_container {
position: absolute;
display: flex;
flex-direction: column;
width: 250px;
display: none;
}
.action_button {
width: 100%;
min-height: 45px;
}
#do_inventory {
border-top: 1px solid #004aa6;
}
#refresh_order {
border-top: 1px solid #004aa6;
border-bottom: 1px solid #004aa6;
}
/* -- Order data */
#order_data_container {
font-size: 1.8rem;
......@@ -148,23 +106,6 @@
border-radius: 3px;
}
#coverage_form > div {
display:inline-block;
float:left;
}
#coverage_form .input-wrapper {
margin-right: 3px;
}
#coverage_days_input, #percent_adjust_input {
display: block;
}
#coverage_days_input {
margin-bottom: 3px;
}
/* -- Table */
#products_table_filter{
text-align: right !important;
......@@ -192,10 +133,6 @@
margin-left: 5px;
}
.main.fa-info-circle {
color: #0275d8;
cursor: pointer;
}
.custom_cell_content {
display: flex;
flex-direction: column;
......@@ -292,15 +229,6 @@
width: 90%;
}
/* product actions modal*/
.npa-options {
width: fit-content;
text-align: left;
margin: auto;
}
.npa-options label {
display: block;
}
/* - Orders created screen */
.order_created_header {
......@@ -358,12 +286,4 @@
background-color: #e7e9ed;
width: 100%;
padding: 15px;
}
/* - Miscellaneous */
footer {
display: none;
}
\ No newline at end of file
from outils.common_imports import *
from outils.for_view_imports import *
from outils.common import OdooAPI
from orders.models import Order, Orders, CagetteSuppliers
from products.models import CagetteProduct, CagetteProducts
......@@ -20,10 +19,7 @@ def helper(request):
'title': 'Aide à la commande',
'couchdb_server': settings.COUCHDB['url'],
'db': settings.COUCHDB['dbs']['orders'],
'odoo_server': settings.ODOO['url'],
'metabase_url': getattr(settings, 'ORDERS_HELPER_METABASE_URL', ''),
'nb_past_days_to_compute_sales_average': OdooAPI().get_system_param('lacagette_products.nb_past_days_to_compute_sales_average'),
'nb_of_consecutive_non_sale_days_considered_as_break': OdooAPI().get_system_param('lacagette_products.nb_of_consecutive_non_sale_days_considered_as_break')
'odoo_server': settings.ODOO['url']
}
template = loader.get_template('orders/helper.html')
......
......@@ -47,7 +47,7 @@ class OdooAPI:
order='id ASC'):
"""Main api request, retrieving data according search conditions."""
fields_and_context = {'fields': fields,
'context': {'lang': 'fr_FR', 'tz': 'Europe/Paris'},
'context': {'lang': 'fr_FR','tz':'Europe/Paris'},
'limit': limit,
'offset': offset,
'order': order
......@@ -59,11 +59,8 @@ class OdooAPI:
def update(self, entity, ids, fields):
"""Update entities which have ids, with new fields values."""
context = {
'context': {'lang': 'fr_FR', 'tz': 'Europe/Paris'}
}
return self.models.execute_kw(self.db, self.uid, self.passwd,
entity, 'write', [ids, fields], context)
entity, 'write', [ids, fields])
def create(self, entity, fields):
"""Create entity instance with given fields values."""
......@@ -77,18 +74,6 @@ class OdooAPI:
def authenticate(self, login, password):
return self.common.authenticate(self.db, login, password, {})
def get_system_param(self, key):
value = ''
try:
res = self.search_read('ir.config_parameter',
[['key', '=', key]],
['value'])
if res:
value = res[0]['value']
except Exception as e:
coop_logger.error('get_system_param: (%s) %s', key, str(e))
return value
class CouchDB:
"""Class to handle interactions with CouchDB"""
......
......@@ -325,16 +325,7 @@
- MEALS_PICKING_TYPE_ID = 10
### New members space
- USE_NEW_MEMBERS_SPACE = True
Should be set to False by default if parameter not set
- START_DATE_FOR_SHIFTS_HISTORY = "2018-01-01"
- AMNISTIE_DATE = "2021-11-24 00:00:00"
In members_space history display a special activity about amnistie
### Miscellious
......
......@@ -187,17 +187,4 @@ footer { position: fixed;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QYFAhkSsdes/QAAA8dJREFUOMvVlGtMW2UYx//POaWHXg6lLaW0ypAtw1UCgbniNOLcVOLmAjHZolOYlxmTGXVZdAnRfXQm+7SoU4mXaOaiZsEpC9FkiQs6Z6bdCnNYruM6KNBw6YWewzl9z+sHImEWv+vz7XmT95f/+3/+7wP814v+efDOV3/SoX3lHAA+6ODeUFfMfjOWMADgdk+eEKz0pF7aQdMAcOKLLjrcVMVX3xdWN29/GhYP7SvnP0cWfS8caSkfHZsPE9Fgnt02JNutQ0QYHB2dDz9/pKX8QjjuO9xUxd/66HdxTeCHZ3rojQObGQBcuNjfplkD3b19Y/6MrimSaKgSMmpGU5WevmE/swa6Oy73tQHA0Rdr2Mmv/6A1n9w9suQ7097Z9lM4FlTgTDrzZTu4StXVfpiI48rVcUDM5cmEksrFnHxfpTtU/3BFQzCQF/2bYVoNbH7zmItbSoMj40JSzmMyX5qDvriA7QdrIIpA+3cdsMpu0nXI8cV0MtKXCPZev+gCEM1S2NHPvWfP/hL+7FSr3+0p5RBEyhEN5JCKYr8XnASMT0xBNyzQGQeI8fjsGD39RMPk7se2bd5ZtTyoFYXftF6y37gx7NeUtJJOTFlAHDZLDuILU3j3+H5oOrD3yWbIztugaAzgnBKJuBLpGfQrS8wO4FZgV+c1IxaLgWVU0tMLEETCos4xMzEIv9cJXQcyagIwigDGwJgOAtHAwAhisQUjy0ORGERiELgG4iakkzo4MYAxcM5hAMi1WWG1yYCJIcMUaBkVRLdGeSU2995TLWzcUAzONJ7J6FBVBYIggMzmFbvdBV44Corg8vjhzC+EJEl8U1kJtgYrhCzgc/vvTwXKSib1paRFVRVORDAJAsw5FuTaJEhWM2SHB3mOAlhkNxwuLzeJsGwqWzf5TFNdKgtY5qHp6ZFf67Y/sAVadCaVY5YACDDb3Oi4NIjLnWMw2QthCBIsVhsUTU9tvXsjeq9+X1d75/KEs4LNOfcdf/+HthMnvwxOD0wmHaXr7ZItn2wuH2SnBzbZAbPJwpPx+VQuzcm7dgRCB57a1uBzUDRL4bfnI0RE0eaXd9W89mpjqHZnUI5Hh2l2dkZZUhOqpi2qSmpOmZ64Tuu9qlz/SEXo6MEHa3wOip46F1n7633eekV8ds8Wxjn37Wl63VVa+ej5oeEZ/82ZBETJjpJ1Rbij2D3Z/1trXUvLsblCK0XfOx0SX2kMsn9dX+d+7Kf6h8o4AIykuffjT8L20LU+w4AZd5VvEPY+XpWqLV327HR7DzXuDnD8r+ovkBehJ8i+y8YAAAAASUVORK5CYII=);
}
.notifyjs-cancelable-base .buttons {width: 190px; margin: 5px auto;}
.notifyjs-cancelable-base button {width: 90px;text-align: center; margin: 3px;}
button.accordion::after {
content: '\002B';
color: #777;
font-weight: bold;
float: right;
margin-left: 5px;
}
button.accordion.active::after {
content: "\2212";
}
.notifyjs-cancelable-base button {width: 90px;text-align: center; margin: 3px;}
\ No newline at end of file
#main_content {text-align: center;}
.param {margin-bottom: 15px;}
.param label {font-weight: bold;}
input.link {min-width: 50em;}
.submit_button {margin-bottom: 10px;}
/* Style the buttons that are used to open and close the accordion panel */
.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
width: 100%;
text-align: left;
border: none;
outline: none;
transition: 0.4s;
}
/* Add a background color to the button if it is clicked on (add the .active class with JS), and when you move the mouse over it (hover) */
.active, .accordion:hover {
background-color: #ccc;
}
/* Style the accordion panel. Note: hidden by default */
.panel {
padding: 0 18px;
background-color: white;
display: none;
overflow: hidden;
}
.param label {font-weight: bold;}
\ No newline at end of file
......@@ -455,22 +455,6 @@ for (i = 0; i < acc.length; i++) {
});
}
$(document).on('click', '.accordion', function(){
/* Toggle between adding and removing the "active" class,
to highlight the button that controls the panel */
this.classList.toggle("active");
/* Toggle between hiding and showing the active panel */
var panel = this.nextElementSibling;
if (panel.style.display === "block") {
panel.style.display = "none";
} else {
panel.style.display = "block";
}
console.log(panel)
});
function report_JS_error(e, m) {
try {
$.post('/log_js_error', {module: m, error: JSON.stringify(e)});
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -83,4 +83,4 @@ function get_module_settings() {
});
}
get_module_settings();
get_module_settings();
\ No newline at end of file
......@@ -7,7 +7,6 @@ import csv
import tempfile
import pymysql.cursors
import datetime
import re
vcats = []
......@@ -173,58 +172,10 @@ class CagetteProduct(models.Model):
return res
@staticmethod
def update_product_internal_ref(product_tmpl_id, default_code):
api = OdooAPI()
res = {}
f = {
'default_code': default_code
}
try:
res["update"] = api.update('product.template', product_tmpl_id, f)
except Exception as e:
res["error"] = str(e)
print(str(e))
return res
@staticmethod
def update_npa_and_minimal_stock(data):
"""Update NPA (ne pas acheter) and minimal stock data"""
res = {}
try:
api = OdooAPI()
f = {'minimal_stock': data['minimal_stock']}
if 'simple-npa' in data['npa']:
f['purchase_ok'] = 0
if 'npa-in-name' in data['npa']:
# Add [NPA] in product name if needed
f['name'] = data['name'] if ('[NPA]' in data['name']) else data['name'] + " [NPA]"
f['purchase_ok'] = 0
elif '[NPA]' in data['name']:
# Remove [NPA] from name
f['name'] = re.sub(r'( \[NPA\])', '', data['name'])
current_name = data['name'] if ('name' not in f) else f['name']
if 'fds-in-name' in data['npa']:
f['name'] = current_name if '[FDS]' in data['name'] else current_name + " [FDS]"
f['purchase_ok'] = 0
elif '[FDS]' in current_name:
f['name'] = re.sub(r'( \[FDS\])', '', current_name)
if len(data['npa']) == 0:
f['purchase_ok'] = 1
res["update"] = api.update('product.template', data['id'], f)
except Exception as e:
res["error"] = str(e)
coop_logger.error("update_npa_and_minimal_stock : %s %s", str(e), str(data))
return res
class CagetteProducts(models.Model):
"""Initially used to make massive barcode update."""
@staticmethod
def get_simple_list():
res = []
......@@ -545,8 +496,7 @@ class CagetteProducts(models.Model):
"uom_id",
"purchase_ok",
"supplier_taxes_id",
"product_variant_ids",
"minimal_stock"
"product_variant_ids"
]
c = [['id', 'in', ptids], ['purchase_ok', '=', True]]
products_t = api.search_read('product.template', c, f)
......
......@@ -10,8 +10,6 @@ urlpatterns = [
url(r'^get_products_stdprices$', views.get_products_stdprices),
url(r'^update_product_stock$', views.update_product_stock),
url(r'^update_product_purchase_ok$', views.update_product_purchase_ok),
url(r'^update_product_internal_ref$', views.update_product_internal_ref),
url(r'^update_npa_and_minimal_stock$', views.update_npa_and_minimal_stock),
url(r'^labels_appli_csv(\/?[a-z]*)$', views.labels_appli_csv, name='labels_appli_csv'),
url(r'^label_print/([0-9]+)/?([0-9\.]*)/?([a-z]*)/?([0-9]*)$', views.label_print),
url(r'^shelf_labels$', views.shelf_labels), # massive print
......
......@@ -3,7 +3,6 @@
from outils.common_imports import *
from outils.for_view_imports import *
from members.models import CagetteUser
from products.models import CagetteProduct
from products.models import CagetteProducts
from inventory.models import CagetteInventory
......@@ -104,51 +103,14 @@ def update_product_stock(request):
def update_product_purchase_ok(request):
res = {}
is_connected_user = CagetteUser.are_credentials_ok(request)
if is_connected_user is True:
data = json.loads(request.body.decode())
data = json.loads(request.body.decode())
res = CagetteProduct.update_product_purchase_ok(data["product_tmpl_id"], data["purchase_ok"])
res = CagetteProduct.update_product_purchase_ok(data["product_tmpl_id"], data["purchase_ok"])
if ('error' in res):
return JsonResponse(res, status=500)
else:
return JsonResponse({"res": res})
else:
return JsonResponse(res, status=403)
def update_product_internal_ref(request):
res = {}
is_connected_user = CagetteUser.are_credentials_ok(request)
if is_connected_user is True:
data = json.loads(request.body.decode())
res = CagetteProduct.update_product_internal_ref(data["product_tmpl_id"], data["default_code"])
if ('error' in res):
return JsonResponse(res, status=500)
else:
return JsonResponse({"res": res})
else:
return JsonResponse(res, status=403)
def update_npa_and_minimal_stock(request):
res = {}
is_connected_user = CagetteUser.are_credentials_ok(request)
if is_connected_user is True:
try:
data = json.loads(request.body.decode())
res = CagetteProduct.update_npa_and_minimal_stock(data)
except Exception as e:
res['error'] = str(e)
coop_logger.error("Update npa and minimal stock : %s", res['error'])
if ('error' in res):
return JsonResponse(res, status=500)
else:
return JsonResponse({"res": res})
if ('error' in res):
return JsonResponse(res, status=500)
else:
return JsonResponse(res, status=403)
return JsonResponse({"res": res})
def labels_appli_csv(request, params):
"""Generate files to put in DAV directory to be retrieved by scales app."""
......
......@@ -996,8 +996,6 @@ function editProductInfo (productToEdit, value = null, batch = false) {
}
firstUpdate = true;
} else if (productToEdit.old_price_unit == newValue) {
productToEdit.new_shelf_price = null;
}
productToEdit.price_unit = newValue;
......
......@@ -125,8 +125,6 @@ class CagetteShift(models.Model):
"shift_type": "standard", # ftop
"related_shift_state": 'confirm',
"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
st_r_id = self.o_api.create('shift.registration', fieldsDatas)
except Exception as e:
......@@ -181,7 +179,7 @@ class CagetteShift(models.Model):
action = 'create'
# Get partner extension ids
cond = [['id', '=', data['idPartner']]]
cond = [['id','=',data['idPartner']]]
fields = ['extension_ids']
partner_extensions = self.o_api.search_read('res.partner', cond, fields)
response = False
......
.main {
.main, .barcode_search_area {
margin-top: 40px;
}
.top_content {
margin-top: 40px;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
}
.top_content_item {
flex: 1 0 33%;
}
#sm_barcode_selector {
border: 1px solid #555;
border-radius:10px;
......@@ -23,6 +11,10 @@
max-width: 60px;
}
#movement_validation_button {
margin-top: 20px;
}
.notifyjs-test1-base {
background: #5CB85C !important;
}
......
......@@ -203,7 +203,7 @@ function init_datatable() {
});
// Show validation button
$('.movement_validation_area').show();
$('.footer').show();
}
}
......@@ -351,7 +351,7 @@ var add_product = function(product) {
}
update_total_value();
$('.movement_validation_area').show(); // if is a second or more access, movement_validation_area is hidden (init_datatable is not fired)
$('.footer').show(); // if is a second or more access, footer is hidden (init_datatable is not fired)
} catch (e) {
err = {msg: e.name + ' : ' + e.message, ctx: 'add_product'};
console.error(err);
......@@ -706,7 +706,7 @@ function do_stock_movement() {
products = [];
products_table.clear().draw();
$('.movement_validation_area').hide();
$('.footer').hide();
},
......
......@@ -20,10 +20,6 @@
<div style="width: 90%" class="fl txtleft">Enveloppe encaissée !</div>
<div style="width: 10%" class="fr txtright"><i class="fas fa-times"></i></div>
</div>
<div id="envelop_deletion_success" class="alert--success clearfix custom_alert" onClick="toggle_deleted_alert()">
<div style="width: 90%" class="fl txtleft">Enveloppe supprimée !</div>
<div style="width: 10%" class="fr txtright"><i class="fas fa-times"></i></div>
</div>
<section class="grid-2 has-gutter">
<section id="cash">
......
......@@ -102,8 +102,6 @@
</div>
<div id="cooperative_state">
</div>
<div id="status_explanation" style="font-weight:bold;">
</div>
<div id="next_shifts">
</div>
</div>
......
{% load static %}
{% block additionnal_css %}
<link rel="stylesheet" href="{% static 'css/members-space-header.css' %}">
{% endblock %}
{% block content %}
<div class="topnav" id="topnav">
<a href="javascript:void(0);" class="nav_item active" id="nav_home">Espace Membre</a>
<a href="javascript:void(0);" class="nav_item" id="nav_my_info">Mes Infos</a>
<a href="javascript:void(0);" class="nav_item" id="nav_my_shifts">Mes Services</a>
<a href="javascript:void(0);" class="nav_item" id="nav_shifts_exchange">Échange de services</a>
<a href="javascript:void(0);" class="nav_item" id="nav_faq">Problèmes et Demandes</a>
<a
href="javascript:void(0);"
target="_blank"
class="nav_item"
id="nav_calendar"
>
Calendrier ABCD
</a>
{# Disconnection button must have this id (logic in all_common.js) #}
<a href="javascript:void(0);" id="deconnect">Déconnexion</a>
<a href="javascript:void(0);" class="icon" onclick="toggleHeader()">
<i class="fa fa-bars"></i>
</a>
</div>
<div class="pairs_info">
<span>
<i class="fas fa-exclamation-circle"></i> Je suis en binôme.
Toutes les actions (changement de service, choix d'un rattrapage...)
ne sont faisables que sur l'espace membre du <b>binôme principal</b>.
Dans mon espace membre, les infos ne sont visibles qu'en lecture seule.
</span>
</div>
<script type="text/javascript" src="{% static 'js/members-space-header.js' %}"></script>
{% endblock %}
<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>
</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 aux formulaires
</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>
{% extends "base.html" %}
{% load static %}
{% block additionnal_css %}
<link rel="stylesheet" href="{% static 'css/datatables/jquery.dataTables.css' %}">
<link rel="stylesheet" href="{% static 'css/datatables/responsive.dataTables.min.css' %}">
<link rel="stylesheet" href="{% static 'fullcalendar-5.9.0/lib/main.min.css' %}">
<link rel="stylesheet" href="{% static "css/members-space.css" %}?v=">
<link rel="stylesheet" href="{% static "css/members-space-my-shifts.css" %}?v=">
<link rel="stylesheet" href="{% static "css/members-space-faq.css" %}?v=">
<link rel="stylesheet" href="{% static "css/members-space-my-info.css" %}?v=">
<link rel="stylesheet" href="{% static "css/members-space-shifts-exchange.css" %}?v=">
{% 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.responsive.min.js' %}"></script>
<script type="text/javascript" src="{% static 'fullcalendar-5.9.0/lib/main.min.js' %}"></script>
<script type="text/javascript" src="{% static 'fullcalendar-5.9.0/lib/locales/fr.js' %}"></script>
{% endblock %}
{% block content %}
<div class="page_body">
{% include "members_space/header.html" %}
<div id="main_content" class="page_content">
</div>
<div id="templates" style="display:none;">
<div id="shift_line_template">
<div class="shift_line">
<i class="fas fa-chevron-right shift_line_chevron"></i>
<span class="shift_line_date"></span> - <span class="shift_line_time"></span>
</div>
</div>
<div id="selectable_shift_line_template">
<div class="selectable_shift_line btn--primary">
<input type="checkbox" class="checkbox">
<div class="selectable_shift_line_text">
<span class="shift_line_date"></span> - <span class="shift_line_time"></span>
</div>
</div>
</div>
<div id="modal_shift_exchange_template">
<div>Je suis sur le point d'échanger le service du : </div>
<div><span class="date_old_shift"></span> à <span class="time_old_shift"></span></div>
<div>par celui du : </div>
<div><span class="date_new_shift"></span> à <span class="time_new_shift"></span></div>
</div>
<div id="modal_add_shift_template">
<div>Je suis sur le point de m'inscrire au service du : <span class="date_new_shift"></span> à <span class="time_new_shift"></span></div>
</div>
<div id="calendar_explaination_template">
<h4>Légende du calendrier</h4>
<a class="example-event fc-daygrid-event fc-daygrid-block-event fc-h-event fc-event fc-event-start fc-event-end fc-event-future shift_booked"><div class="fc-event-main"><div class="fc-event-main-frame"><div class="fc-event-time">06:00</div><div class="fc-event-title-container"><div class="fc-event-title fc-sticky">&nbsp;- 9/12</div></div></div></div></a>
<p>Un service colorié en noir : je suis déjà inscrit.e à ce service.</p>
<a class="example-event fc-daygrid-event fc-daygrid-block-event fc-h-event fc-event fc-event-start fc-event-end fc-event-future shift_less_alf"><div class="fc-event-main"><div class="fc-event-main-frame"><div class="fc-event-time">10:45</div><div class="fc-event-title-container"><div class="fc-event-title fc-sticky">&nbsp;- 3/12</div></div></div></div></a>
<p>Un service colorié en bleu : je peux m'inscrire à ce service.</p>
<p>3/12 <i class="arrow_explanation_numbers fas fa-arrow-right"></i> il y a déjà 3 places réservées à ce service sur 12 disponibles.
<b>Plus le chiffre de gauche est petit, plus on a besoin de coopérateurs.rices à ce service !</b></p>
</div>
<div id="cant_have_delay_msg_template">
<h3>Bonjour, tu avais 6 mois pour rattraper tes services manqués et il semblerait que tu ne l'aies pas fait.</h3>
<h3>Tu ne peux plus sélectionner de rattrapages sur ton espace membre pour le moment,
merci de contacter le bureau des membres pour résoudre ce problème en remplissant ce formulaire : </h3>
</div>
<div id="comite_template">
<h3>Vous êtes inscrit.e dans le service des comités, vous n'avez pas accès au calendrier d'échange des services car vous vous organisez directement avec le responsable du comité. Si vous avez des rattrapages à réaliser, merci de contacter le responsable du comité qui vous aidera à planifier les rattrapages ou trouver une solution.</h3>
<h3>Le calendrier ci-dessous est en lecture seule</h3>
</div>
</div>
</div>
<script>
var app_env = '{{app_env}}';
var forms_link = '{{forms_link}}';
var unsuscribe_form_link = '{{unsuscribe_form_link}}';
var request_form_link = '{{request_form_link}}';
var late_service_form_link = '{{late_service_form_link}}';
var change_template_form_link = '{{change_template_form_link}}';
var associated_subscribe_form_link = '{{associated_subscribe_form_link}}';
var associated_unsubscribe_form_link = '{{associated_unsubscribe_form_link}}';
var template_unsubscribe_form_link = '{{template_unsubscribe_form_link}}';
var change_email_form_link = '{{change_email_form_link}}';
var coop_unsubscribe_form_link = '{{coop_unsubscribe_form_link}}';
var sick_leave_form_link = '{{sick_leave_form_link}}';
var underage_subscribe_form_link = '{{underage_subscribe_form_link}}';
var helper_subscribe_form_link = '{{helper_subscribe_form_link}}';
var helper_unsubscribe_form_link = '{{helper_unsubscribe_form_link}}';
var covid_form_link = '{{covid_form_link}}';
var covid_end_form_link = '{{covid_end_form_link}}';
var member_cant_have_delay_form_link = '{{member_cant_have_delay_form_link}}';
var abcd_calendar_link = "{{abcd_calendar_link}}"
var days_to_hide = "{{daysToHide}}"
var partner_data = {
"partner_id":"{{partnerData.id}}",
"name":"{{partnerData.display_name}}",
"shift_type":"{{partnerData.shift_type}}",
"date_delay_stop":"{{partnerData.date_delay_stop}}",
"cooperative_state":"{{partnerData.cooperative_state}}",
"regular_shift_name":"{{partnerData.regular_shift_name}}",
"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}}",
"zip" : "{{partnerData.zip}}",
"city" : "{{partnerData.city}}",
"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}}",
"associated_partner_id" : "{{partnerData.associated_partner_id}}",
"associated_partner_name" : "{{partnerData.associated_partner_name}}",
"verif_token" : "{{partnerData.verif_token}}",
"leave_stop_date": "{{partnerData.leave_stop_date}}",
"comite": "{{partnerData.comite}}"
}
</script>
<script src="{% static "js/all_common.js" %}?v="></script>
<script src="{% static "js/members-space-home.js" %}?v="></script>
<script src="{% static "js/members-space-my-info.js" %}?v="></script>
<script src="{% static "js/members-space-my-shifts.js" %}?v="></script>
<script src="{% static "js/members-space-faq.js" %}?v="></script>
<script src="{% static "js/members-space-shifts-exchange.js" %}?v="></script>
<script src="{% static "js/members-space.js" %}?v="></script>
{% endblock %}
<div id="my_info">
<div class="page_title txtcenter">
<h1>Mes Infos</h1>
</div>
<div class="tiles_container">
<div class="tile full_width_tile" id="my_info_area">
<div class="tile_title">
<i class="fas fa-user tile_icon"></i>
<span class="member_info member_name"></span>
</div>
<div class="tile_content" id="my_info_content">
<div class="my_info_line">
<div class="my_info_line_left">
Statut
</div>
<div class="my_info_line_right">
<p class="member_info member_status"></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>
</div>
</div>
</div>
<div class="my_info_line">
<div class="my_info_line_left">
Créneau
</div>
<div class="my_info_line_right member_shift_name_area">
<span class="member_shift_name member_info"></span>
</div>
</div>
<div class="my_info_line">
<div class="my_info_line_left">
Numéro de coop
</div>
<div class="my_info_line_right member_coop_number_area">
<span class="member_coop_number member_info"></span>
</div>
</div>
<div class="my_info_line member_email_line">
<div class="my_info_line_left">
Email
</div>
<div class="my_info_line_right member_email_area">
<span class="member_email member_info"></span>
</div>
</div>
<div class="my_info_line member_address_line">
<div class="my_info_line_left">
Adresse
</div>
<div class="my_info_line_right member_address_area" id="edit_address_value">
<span class="member_address member_info"></span><br>
<span id="edit_address"><i class="fas fa-edit tile_icon edit-btn" ></i></span>
</div>
<div class="my_info_line_right member_address_area1" id="edit_address_form">
<input type="text" name="street_form" id="street_form" placeholder="Rue"> <br>
<!-- <input type="text" name="street2_form" id="street2_form" placeholder="Complément"> -->
<input type="text" name="zip_form" id="zip_form" placeholder="Code postal"> <br>
<input type="text" name="city_form" id="city_form" placeholder="Ville"> <br>
<span id="cancel_edit_address"><i class="fas fa-times tile_icon edit-btn"></i></span>
<span id="save_edit_address"><i class="fas fa-check tile_icon edit-btn"></i></span>
</div>
</div>
<div class="my_info_line member_phone_line">
<div class="my_info_line_left">
Téléphone
</div>
<div class="my_info_line_right member_phone_area" id="edit_phone_value">
<span class="member_phone member_info"></span>
<span class="member_mobile member_info"></span>
<span id="edit_phone"><i class="fas fa-edit tile_icon edit-btn" ></i></span>
</div>
<div class="my_info_line_right member_phone_area1" id="edit_phone_form">
<input type="text" name="phone" id="phone_form" placeholder="Tel fixe"> <br>
<input type="text" name="mobile" id="mobile_form" placeholder="Tel mobile"><br>
<span id="cancel_edit_phone"><i class="fas fa-times tile_icon edit-btn"></i></span>
<span id="save_edit_phone"><i class="fas fa-check tile_icon edit-btn"></i></span>
</div>
</div>
</div>
</div>
<div class="tile full_width_tile" id="attached_info_area">
<div class="tile_title">
Mon Binôme
</div>
<div class="tile_content" id="attached_info">
<div class="my_info_line attached_partner_name_line">
<div class="my_info_line_left">
Je suis en binôme avec :
</div>
<div class="my_info_line_right attached_partner_name_area">
<span class="attached_partner_name member_info"></span>
</div>
</div>
</div>
</div>
<div class="tile full_width_tile">
<div class="tile_title">
Comprendre mon statut
</div>
<div class="my_info_line_middle">
Il existe différents statuts à La Cagette donnant ou non le droit de faire ses courses. Voici un schéma explicatif expliquant le passage d'un statut à un autre. Pour toute question relative aux statuts, rendez&#x2011;vous dans la rubrique <a href='faq'>Problèmes&nbsp;&&nbsp;Demandes</a>.
</div>
<a href="/static/img/diagramme_etat_statut_cooperateurs.png" target=”_blank”>
<img class="status_info_image" src="/static/img/diagramme_etat_statut_cooperateurs.png" alt="diagramme_etat_statut_cooperateurs"/>
</a>
</div>
</div>
</div>
<div id="shifts_exchange">
<div id="unsuscribed_content" class="shifts_exchange_page_content">
<h3>Je suis désinscrit.e, je dois remplir un formulaire pour qu'on me réinscrive à un créneau.</h3>
<a href="#" target="_blank" class="btn--warning unsuscribed_form_link">
J'accède au formulaire
</a>
</div>
<div id="suspended_cant_have_delay_content" class="shifts_exchange_page_content">
<div class="suspended_cant_have_delay_msg"></div>
<a href="#" target="_blank" class="btn--warning cant_have_delay_form_link">
J'accède au formulaire
</a>
</div>
<div id="comite_content" class="shifts_exchange_page_content">
<div class="comite_content_msg"></div>
<div id="read_only_calendar"></div>
</div>
<div id="suspended_content" class="shifts_exchange_page_content">
<h3>
J'ai <span class="makeups_nb"></span> rattrapage(s) à effectuer, je dois le(s) sélectionner pour pouvoir refaire mes courses.
J'ai 6 mois de délai pour le(s) rattraper.
</h3>
<h3>
Si besoin, je peux contacter le Bureau des membres via la rubrique "J'ai une demande" pour expliquer ma situation.
</h3>
<button type="button" class="btn--danger select_makeups">
Je sélectionne mes rattrapages
</button>
</div>
<div id="shifts_exchange_content" class="shifts_exchange_page_content">
<div id="need_to_select_makeups_message">
<span class="select_makeups_message_block">
<i class="fas fa-exclamation-triangle makeups_warning"></i>
J'ai <span class="makeups_nb"></span> rattrapage(s) à faire. </span>
<span class="select_makeups_message_block">Je dois les sélectionner dans le calendrier. </span>
<span class="select_makeups_message_block">Je ne peux pas échanger de service tant que je n'ai pas choisi mes rattrapages. </span>
</div>
<div id="calendar_top_info">
<div id="partner_shifts_list">
<h4>Liste de mes services :</h4>
<div class="loading-incoming-shifts">
<i class="fas fa-spinner fa-spin fa-lg"></i>
</div>
<div id="shifts_list"></div>
</div>
<div id="calendar_explaination_area"></div>
<button id="calendar_explaination_button" class="btn--success">Légende du calendrier</button>
</div>
<div class="loading-calendar">
<i class="fas fa-spinner fa-spin fa-2x"></i>
</div>
<div id="calendar"></div>
</div>
</div>
<div>
<button type="button" class="accordion" style="width:100%"><label>Comment sont calculées les conso. moyennes / jour ?</label></button>
<div class="txtleft" style="display: none;">
<p>
La fonction qui calcule les consommations moyennes prend en paramètre une date de départ. <br/>
Si elle n'est pas indiquée, la date prise en compte sera "<em>aujourd'hui - nb de jours paramétré dans Odoo</em>".<br/>
Ce nombre de jours paramétrable se trouve en suivant les menus suivants :<br>
Configuration > Technique > Paramètres > Paramètres systèmes. <br/>
La valeur est définie avec la clef "<em>lacagette_products.nb_past_days_to_compute_sales_average</em>".<br/>
Ce paramètre vaut <strong>{{nb_past_days_to_compute_sales_average}}</strong> au moment du chargement de cette page.<br/>
Les ventes du dimanche sont exclues du calcul.<br/>
</p>
<p>
Une requête est faite sur l'ensemble des passages en caisse, de la date de départ à hier, récupérant pour tous les jours de la période (dimanches exclus) les quantités vendues des articles achetés chez le fournisseur.<br/>
Pour chaque article, le nombre de jours considérés pour faire la moyenne est défini commme suit :<br/>
<em>Nb de jours ouvrés de la période - Nb de jours des périodes de rupture</em><br/>
Les périodes de ruptures sont caractérisées par un nombre de jours consécutifs assez important de jours sans vente de l'article.<br/>
Le nombre de jours consécutifs sans vente pour considérer l'article en rupture est actuellement de <strong>{{nb_of_consecutive_non_sale_days_considered_as_break}}</strong><br/>
(c'est le paramètre système avec la clef "<em>lacagette_products.nb_of_consecutive_non_sale_days_considered_as_break</em>").<br/>
</p>
<p>
Pour chaque article, la consommation moyenne par jour est obtenue en divisant la quantité totale vendue sur la période par le nombre de jours significatifs.
</p>
</div>
</div>
<div>
<button type="button" class="accordion" style="width:100%"><label>Comment sont calculés les besoins ?</label></button>
<div class="txtleft" style="display: none;">
La quantité à commander pour couvrir les besoins (en jours) est le résultat de :
<p>
(<em>nb_jours</em> <strong>x</strong> <em>conso_moyenne</em>) <strong>-</strong> <em>stock_existant</em> <strong>-</strong> <em>quantités_entrantes</em> <strong>+</strong> <em>stock_minimum</em>
</p>
</div>
</div>
......@@ -40,32 +40,10 @@
<button type="button" class="btn--danger" id="back_to_order_selection_from_main">
<i class="fas fa-arrow-left"></i>&nbsp; Retour
</button>
<div class="right_action_buttons">
<div id="actions_buttons_wrapper">
<button type="button" class='btn--primary' id="toggle_action_buttons">
<span class="button_content">
Actions
</span>
<span class="toggle_action_buttons_icon">
<i class="fas fa-chevron-down"></i>
</span>
</button>
<div id="actions_buttons_container">
<button type="button" class='btn--primary action_button' id="do_inventory" style="display:none;">
Faire un inventaire
</button>
<button type="button" class='btn--primary action_button' id="refresh_order">
Rafraîchir la commande
</button>
<button type="button" class='btn--danger action_button' id="delete_order_button">
Supprimer la commande
</button>
</div>
</div>
<a class='btn--warning link_as_button' id="access_metabase" style="display:none;" href="{{metabase_url}}" target="_blank">
Stats Métabase
</a>
<div class="rights_buttons">
<button type="button" class='btn--primary' id="do_inventory" style="display:none;">
Faire un inventaire
</button>
</div>
</div>
......@@ -79,27 +57,9 @@
</div>
<div class="txtcenter" id="order_forms_container">
<form action="javascript:;" id="supplier_form" class="order_form_item">
<input type="text" name="supplier" id="supplier_input" placeholder="Rechercher un fournisseur par son nom">
<button type="submit" class='btn--primary'>Ajouter le fournisseur</button>
</form>
<form action="javascript:;" id="stats_date_from_form" class="order_form_item">
<label for="stats_date_period_select">Période de calcul de la conso moyenne </label>
<select name="stats_date_period_select" id="stats_date_period_select">
<option value="">Par défaut</option>
<option value="1week">1 semaine</option>
<option value="2weeks">2 semaines</option>
</select>
</form>
<form action="javascript:;" id="coverage_form" class="order_form_item">
<div class="input-wrapper">
<input type="number" name="coverage_days" id="coverage_days_input" placeholder="Nb jours de couverture" min="1">
<input type="number" name="percent_adjustement" id="percent_adjust_input" placeholder="ajustement en %">
</div>
<div>
<button type="submit" class='btn--primary'>Calculer les besoins</button> <i class='main fa fa-info-circle fa-lg'></i>
</div>
<form action="javascript:;" id="coverage_form">
<input type="number" name="coverage_days" id="coverage_days_input" placeholder="Nb jours de couverture" min="1">
<button type="submit" class='btn--primary'>Calculer les besoins</button>
</form>
<form action="javascript:;" id="supplier_form">
<input type="text" name="supplier" id="supplier_input" placeholder="Rechercher un fournisseur par son nom">
......@@ -250,21 +210,14 @@
<hr/>
</div>
<div id="modal_product_actions">
Actions sur <h3><span class="product_name"></span></h3>
<p>
<h4>NPA</h4>
<div class="npa-options">
<label><input type="checkbox" name="npa-actions" value="simple-npa" /> Mettre le produit en NPA </label>
<label><input type="checkbox" name="npa-actions" value="npa-in-name" /> Mettre le produit en NPA et afficher NPA</label>
<label><input type="checkbox" name="npa-actions" value="fds-in-name" /> Mettre le produit en NPA et afficher FDS</label>
</div>
</p>
<div id="modal_product_npa">
<h3>Attention !</h3>
<p>
<h4>Stock minimum</h4>
<input type="number" name="minimal_stock" value="" />
Vous vous apprêtez à passer le produit <span class="product_name"></span> en <span class="product_npa"></span>.<br/>
Dès que vous aurez cliqué sur "Valider", le produit sera retiré du tableau et l'information sera enregistrée dans Odoo.
</p>
<p>Êtez-vous sûr ?</p>
<hr/>
</div>
<div id="modal_create_order">
......@@ -281,9 +234,7 @@
<br/>
<hr/>
</div>
<div id="explanations">
{% include "orders/explanations.html" %}
</div>
<div id="modal_create_order__supplier_date_planned">
<div class="modal_input_area">
<span class="modal_input_label supplier_name"></span>
......
......@@ -48,28 +48,22 @@
<p><i>Vous pouvez également taper le codebarre, puis appuyer sur la touche Entrée.</i></p>
</div>
<div class="top_content">
<div class="top_content_item top_content_left">
<div class="movement_validation_area txtcenter" style="display:none">
<h4>Total (H.T.) : <span class="total_value">0</span></h4>
<button type="button" class="btn--primary" id="movement_validation_button" name="button">Validation du total des produits saisis</button>
<div class="barcode_search_area txtcenter">
<input type="text" id="sm_barcode_selector" placeholder="Codebarre">
<div id="icon_product_not_found" class="tooltip" style="display:none;">
<span class="tooltiptext tooltip-lg tt_twolines">Aucun produit trouvé avec ce code-barre.</span>
<span style="color: #d9534f;"> <i class="fas fa-ban"></i>
</div>
</div>
<div class="barcode_search_area txtcenter top_content_item top_content_left">
<input type="text" id="sm_barcode_selector" placeholder="Codebarre">
<div id="icon_product_not_found" class="tooltip" style="display:none;">
<span class="tooltiptext tooltip-lg tt_twolines">Aucun produit trouvé avec ce code-barre.</span>
<span style="color: #d9534f;"> <i class="fas fa-ban"></i>
</div>
</div>
<div class="top_content_item top_content_left"></div>
</div>
<div class="main">
<table id="products_table" class="display" cellspacing="0" ></table>
</div>
<div class="footer txtcenter" style="display:none">
<h4>Total (H.T.) : <span class="total_value">0</span></h4>
<button type="button" class="btn--primary" id="movement_validation_button" name="button">Validation du total des produits saisis</button>
</div>
<input type="hidden" name="barcode"/>
</div>
......
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