Commit a7ecd0d6 by Félicie

Merge branch 'evolution_bdm' of gl.cooperatic.fr:cooperatic-foodcoops/third-party into ticket_1680

parents c31c58a7 934b8216
...@@ -134,5 +134,5 @@ BLOCK_SERVICE_EXCHANGE_24H_BEFORE = True ...@@ -134,5 +134,5 @@ BLOCK_SERVICE_EXCHANGE_24H_BEFORE = True
ORDERS_HELPER_METABASE_URL = "url_meta_base" ORDERS_HELPER_METABASE_URL = "url_meta_base"
# New members space # New members space
USE_NEW_MEMBERS_SPACE = True USE_NEW_MEMBERS_SPACE = True
START_DATE_FOR_POINTS_HISTORY = "2018-01-01" START_DATE_FOR_SHIFTS_HISTORY = "2018-01-01"
...@@ -109,14 +109,14 @@ def add_pts_to_everybody(request, pts, reason): ...@@ -109,14 +109,14 @@ def add_pts_to_everybody(request, pts, reason):
is_connected_user = CagetteUser.are_credentials_ok(request) is_connected_user = CagetteUser.are_credentials_ok(request)
if is_connected_user is True: if is_connected_user is True:
try: try:
fields = ['in_ftop_team'] fields = ['shift_type']
cond = [['is_member', '=', True]] cond = [['is_member', '=', True]]
all_members = CagetteMembers.get(cond, fields) all_members = CagetteMembers.get(cond, fields)
if all_members and len(all_members) > 0: if all_members and len(all_members) > 0:
ftop_ids = [] ftop_ids = []
standard_ids = [] standard_ids = []
for m in all_members: for m in all_members:
if m['in_ftop_team'] is True: if m['shift_type'] == 'ftop':
ftop_ids.append(m['id']) ftop_ids.append(m['id'])
else: else:
standard_ids.append(m['id']) standard_ids.append(m['id'])
......
...@@ -21,7 +21,7 @@ FUNDRAISING_CAT_ID = {'A': 1, 'B': 2, 'C': 3} ...@@ -21,7 +21,7 @@ FUNDRAISING_CAT_ID = {'A': 1, 'B': 2, 'C': 3}
class CagetteMember(models.Model): class CagetteMember(models.Model):
"""Class to handle cagette Odoo member.""" """Class to handle cagette Odoo member."""
m_default_fields = ['name', 'parent_name', 'sex', 'image_medium', 'active', m_default_fields = ['name', 'parent_name', 'sex', 'image_medium', 'active',
'barcode_base', 'barcode', 'in_ftop_team', 'barcode_base', 'barcode', 'shift_type',
'is_associated_people', 'is_member', 'shift_type', 'is_associated_people', 'is_member', 'shift_type',
'display_ftop_points', 'display_std_points', 'display_ftop_points', 'display_std_points',
'is_exempted', 'cooperative_state', 'date_alert_stop'] 'is_exempted', 'cooperative_state', 'date_alert_stop']
...@@ -118,19 +118,25 @@ class CagetteMember(models.Model): ...@@ -118,19 +118,25 @@ class CagetteMember(models.Model):
fields = ['name', 'email', 'birthdate', 'create_date', 'cooperative_state', 'is_associated_people'] fields = ['name', 'email', 'birthdate', 'create_date', 'cooperative_state', 'is_associated_people']
res = api.search_read('res.partner', cond, fields) res = api.search_read('res.partner', cond, fields)
if (res and len(res) >= 1): if (res and len(res) >= 1):
coop_id = None
for item in res: for item in res:
coop = item coop = item
if item["birthdate"] is not False:
coop_birthdate = item['birthdate']
coop_state = item['cooperative_state']
if item["is_associated_people"] == True: if item["is_associated_people"] == True:
break coop_id = item['id']
y, m, d = coop['birthdate'].split('-') y, m, d = coop_birthdate.split('-')
password = password.replace('/', '') password = password.replace('/', '')
if (password == d + m + y): if (password == d + m + y):
data['id'] = coop['id'] if coop_id is None:
coop_id = coop['id']
data['id'] = coop_id
auth_token_seed = fp + coop['create_date'] auth_token_seed = fp + coop['create_date']
data['auth_token'] = hashlib.sha256(auth_token_seed.encode('utf-8')).hexdigest() data['auth_token'] = hashlib.sha256(auth_token_seed.encode('utf-8')).hexdigest()
data['token'] = hashlib.sha256(coop['create_date'].encode('utf-8')).hexdigest() data['token'] = hashlib.sha256(coop['create_date'].encode('utf-8')).hexdigest()
data['coop_state'] = coop['cooperative_state'] data['coop_state'] = coop_state
if not ('auth_token' in data): if not ('auth_token' in data):
data['failure'] = True data['failure'] = True
...@@ -799,6 +805,20 @@ class CagetteMember(models.Model): ...@@ -799,6 +805,20 @@ class CagetteMember(models.Model):
res['error'] = str(e) res['error'] = str(e)
return res return res
def search_associated_people(self):
""" Search for an associated partner """
res = {}
c = [["parent_id", "=", self.id]]
f = ["id", "name", "barcode_base"]
res = self.o_api.search_read('res.partner', c, f)
try:
return res[0]
except:
return None
class CagetteMembers(models.Model): class CagetteMembers(models.Model):
"""Class to manage operations on all members or part of them.""" """Class to manage operations on all members or part of them."""
...@@ -1117,24 +1137,26 @@ class CagetteServices(models.Model): ...@@ -1117,24 +1137,26 @@ class CagetteServices(models.Model):
def get_services_at_time(time, tz_offset, with_members=True): def get_services_at_time(time, tz_offset, with_members=True):
"""Retrieve present services with member linked.""" """Retrieve present services with member linked."""
# import operator default_acceptable_minutes_after_shift_begins = getattr(settings, 'ACCEPTABLE_ENTRANCE_MINUTES_AFTER_SHIFT_BEGINS', 15)
min_before_shift_starts_delay = 20 minutes_before_shift_starts_delay = getattr(settings, 'ACCEPTABLE_ENTRANCE_MINUTES_BEFORE_SHIFT', 15)
min_after_shift_starts_delay = 20 minutes_after_shift_starts_delay = default_acceptable_minutes_after_shift_begins
late_mode = getattr(settings, 'ENTRANCE_WITH_LATE_MODE', False) late_mode = getattr(settings, 'ENTRANCE_WITH_LATE_MODE', False)
max_duration = getattr(settings, 'MAX_DURATION', 180)
if late_mode is True: if late_mode is True:
min_before_shift_starts_delay = getattr(settings, 'ENTRANCE_VALIDATION_GRACE_DELAY', 60) minutes_after_shift_starts_delay = getattr(settings, 'ENTRANCE_VALIDATION_GRACE_DELAY', 60)
min_after_shift_starts_delay = 0
api = OdooAPI() api = OdooAPI()
now = dateutil.parser.parse(time) - datetime.timedelta(minutes=tz_offset) now = dateutil.parser.parse(time) - datetime.timedelta(minutes=tz_offset)
start1 = now - datetime.timedelta(minutes=min_before_shift_starts_delay) start1 = now + datetime.timedelta(minutes=minutes_before_shift_starts_delay)
start2 = now + datetime.timedelta(minutes=min_after_shift_starts_delay) start2 = now - datetime.timedelta(minutes=minutes_after_shift_starts_delay)
cond = [['date_begin_tz', '>=', start1.isoformat()], end = start1 + datetime.timedelta(minutes=max_duration)
['date_begin_tz', '<=', start2.isoformat()]] cond = [['date_end_tz', '<=', end.isoformat()]]
cond.append('|')
cond.append(['date_begin_tz', '>=', start1.isoformat()])
cond.append(['date_begin_tz', '>=', start2.isoformat()])
fields = ['name', 'week_number', 'registration_ids', fields = ['name', 'week_number', 'registration_ids',
'standard_registration_ids', 'standard_registration_ids',
'shift_template_id', 'shift_ticket_ids', 'shift_template_id', 'shift_ticket_ids',
'date_begin_tz', 'date_end_tz'] 'date_begin_tz', 'date_end_tz']
## return (start1.isoformat(), start2.isoformat())
services = api.search_read('shift.shift', cond, fields,order ="date_begin_tz ASC") services = api.search_read('shift.shift', cond, fields,order ="date_begin_tz ASC")
for s in services: for s in services:
if (len(s['registration_ids']) > 0): if (len(s['registration_ids']) > 0):
...@@ -1143,7 +1165,7 @@ class CagetteServices(models.Model): ...@@ -1143,7 +1165,7 @@ class CagetteServices(models.Model):
now.replace(tzinfo=None) now.replace(tzinfo=None)
- -
dateutil.parser.parse(s['date_begin_tz']).replace(tzinfo=None) dateutil.parser.parse(s['date_begin_tz']).replace(tzinfo=None)
).seconds / 60 > min_after_shift_starts_delay ).total_seconds() / 60 > default_acceptable_minutes_after_shift_begins
if with_members is True: if with_members is True:
cond = [['id', 'in', s['registration_ids']], ['state', '!=', 'cancel']] cond = [['id', 'in', s['registration_ids']], ['state', '!=', 'cancel']]
fields = ['partner_id', 'shift_type', 'state'] fields = ['partner_id', 'shift_type', 'state']
...@@ -1211,14 +1233,17 @@ class CagetteServices(models.Model): ...@@ -1211,14 +1233,17 @@ class CagetteServices(models.Model):
return api.update('shift.registration', [int(reg_id)], f) return api.update('shift.registration', [int(reg_id)], f)
@staticmethod @staticmethod
def record_absences(): def record_absences(date):
"""Called by cron script.""" """Called by cron script."""
import dateutil.parser import dateutil.parser
if len(date) > 0:
now = dateutil.parser.parse(date)
else:
now = datetime.datetime.now() now = datetime.datetime.now()
# now = dateutil.parser.parse('2020-09-15T15:00:00Z') # now = dateutil.parser.parse('2020-09-15T15:00:00Z')
date_24h_before = now - datetime.timedelta(hours=24) date_24h_before = now - datetime.timedelta(hours=24)
# let authorized people time to set presence for those who came in late # let authorized people time to set presence for those who came in late
end_date = now - datetime.timedelta(hours=3) end_date = now - datetime.timedelta(hours=2)
api = OdooAPI() api = OdooAPI()
absence_status = 'excused' absence_status = 'excused'
res_c = api.search_read('ir.config_parameter', res_c = api.search_read('ir.config_parameter',
...@@ -1250,7 +1275,10 @@ class CagetteServices(models.Model): ...@@ -1250,7 +1275,10 @@ class CagetteServices(models.Model):
if int(_h) < 21: if int(_h) < 21:
ids.append(int(r['id'])) ids.append(int(r['id']))
f = {'state': absence_status} f = {'state': absence_status}
return {'update': api.update('shift.registration', ids, f), 'reg_shift': res} update_shift_reg_result = {'update': api.update('shift.registration', ids, f), 'reg_shift': res}
if update_shift_reg_result['update'] is True:
update_shift_reg_result['process_status_res'] = api.execute('res.partner','run_process_target_status', [])
return update_shift_reg_result
@staticmethod @staticmethod
def close_ftop_service(): def close_ftop_service():
......
...@@ -43,7 +43,7 @@ h1 .member_name {font-weight: bold;} ...@@ -43,7 +43,7 @@ h1 .member_name {font-weight: bold;}
{border:1px solid #000; border-radius: 5px; padding:5px; margin-bottom:15px;background:#FFF;} {border:1px solid #000; border-radius: 5px; padding:5px; margin-bottom:15px;background:#FFF;}
.members_list {list-style: none;} .members_list {list-style: none;}
.members_list li {display:block;margin-bottom:5px;} .members_list li {display:block;margin-bottom:5px;}
.members_list.late li {color: #de9b00;} .members_list.late li {background-color: #de9b00; color: white}
.members_list li.btn--inverse {background: #449d44 !important; cursor:not-allowed; color: #FFF; } .members_list li.btn--inverse {background: #449d44 !important; cursor:not-allowed; color: #FFF; }
#service_entry_success {font-size: x-large;} #service_entry_success {font-size: x-large;}
......
...@@ -394,7 +394,7 @@ function fill_service_entry_sucess(member) { ...@@ -394,7 +394,7 @@ function fill_service_entry_sucess(member) {
var points = member.display_std_points; var points = member.display_std_points;
if (member.in_ftop_team == true) { if (member.shift_type == 'ftop') {
points = member.display_ftop_points; points = member.display_ftop_points;
} }
pages.service_entry_success.find('span.points').text(points); pages.service_entry_success.find('span.points').text(points);
...@@ -410,7 +410,7 @@ function fill_service_entry_sucess(member) { ...@@ -410,7 +410,7 @@ function fill_service_entry_sucess(member) {
var service_verb = 'est prévu'; var service_verb = 'est prévu';
if (member.next_shift) { if (member.next_shift) {
if (member.in_ftop_team == true if (member.shift_type == 'ftop'
&& member.next_shift.shift_type == "ftop") { && member.next_shift.shift_type == "ftop") {
var start_elts = member.next_shift.start.split(' à '); var start_elts = member.next_shift.start.split(' à ');
...@@ -468,7 +468,7 @@ function fill_rattrapage_2() { ...@@ -468,7 +468,7 @@ function fill_rattrapage_2() {
var msg = "Bienvenue pour ton rattrapage !"; var msg = "Bienvenue pour ton rattrapage !";
var shift_ticket_id = selected_service.shift_ticket_ids[0]; var shift_ticket_id = selected_service.shift_ticket_ids[0];
if (current_displayed_member.in_ftop_team == true) { if (current_displayed_member.shift_type == 'ftop') {
msg ="Bienvenue dans ce service !"; msg ="Bienvenue dans ce service !";
if (selected_service.shift_ticket_ids[1]) if (selected_service.shift_ticket_ids[1])
shift_ticket_id = selected_service.shift_ticket_ids[1]; shift_ticket_id = selected_service.shift_ticket_ids[1];
......
...@@ -40,7 +40,7 @@ urlpatterns = [ ...@@ -40,7 +40,7 @@ urlpatterns = [
url(r'^save_photo/([0-9]+)$', views.save_photo, name='save_photo'), url(r'^save_photo/([0-9]+)$', views.save_photo, name='save_photo'),
url(r'^services_at_time/([0-9TZ\-\: \.]+)/([0-9\-]+)$', views.services_at_time), url(r'^services_at_time/([0-9TZ\-\: \.]+)/([0-9\-]+)$', views.services_at_time),
url(r'^service_presence/$', views.record_service_presence), url(r'^service_presence/$', views.record_service_presence),
url(r'^record_absences$', views.record_absences), url(r'^record_absences/?([0-9\-\ \:]*)$', views.record_absences),
url(r'^close_ftop_service$', views.close_ftop_service), url(r'^close_ftop_service$', views.close_ftop_service),
url(r'^get_credentials$', views.get_credentials), url(r'^get_credentials$', views.get_credentials),
url(r'^remove_data_from_couchdb$', views.remove_data_from_CouchDB), url(r'^remove_data_from_couchdb$', views.remove_data_from_CouchDB),
......
...@@ -29,7 +29,8 @@ def index(request): ...@@ -29,7 +29,8 @@ def index(request):
'ENTRANCE_EASY_SHIFT_VALIDATE_MSG': getattr(settings, 'ENTRANCE_EASY_SHIFT_VALIDATE_MSG', 'ENTRANCE_EASY_SHIFT_VALIDATE_MSG': getattr(settings, 'ENTRANCE_EASY_SHIFT_VALIDATE_MSG',
'Je valide mon service "Comité"'), 'Je valide mon service "Comité"'),
'CONFIRME_PRESENT_BTN' : getattr(settings, 'CONFIRME_PRESENT_BTN', 'Présent.e'), 'CONFIRME_PRESENT_BTN' : getattr(settings, 'CONFIRME_PRESENT_BTN', 'Présent.e'),
'LATE_MODE': getattr(settings, 'ENTRANCE_WITH_LATE_MODE', False) 'LATE_MODE': getattr(settings, 'ENTRANCE_WITH_LATE_MODE', False),
'ENTRANCE_VALIDATE_PRESENCE_MESSAGE' : getattr(settings, 'ENTRANCE_VALIDATE_PRESENCE_MESSAGE', '')
} }
for_shoping_msg = getattr(settings, 'ENTRANCE_COME_FOR_SHOPING_MSG', '') for_shoping_msg = getattr(settings, 'ENTRANCE_COME_FOR_SHOPING_MSG', '')
...@@ -281,7 +282,8 @@ def record_service_presence(request): ...@@ -281,7 +282,8 @@ def record_service_presence(request):
import re import re
o_date = re.search(r'/([^\/]+?)$', request.META.get('HTTP_REFERER')) o_date = re.search(r'/([^\/]+?)$', request.META.get('HTTP_REFERER'))
if o_date: if o_date:
overrided_date = o_date.group(1) overrided_date = re.sub(r'(%20)',' ', o_date.group(1))
# rid = 0 => C'est un rattrapage, sur le service # rid = 0 => C'est un rattrapage, sur le service
if sid > 0 and stid > 0: if sid > 0 and stid > 0:
# Add member to service and take presence into account # Add member to service and take presence into account
...@@ -289,7 +291,6 @@ def record_service_presence(request): ...@@ -289,7 +291,6 @@ def record_service_presence(request):
if res['rattrapage'] is True: if res['rattrapage'] is True:
res['update'] = 'ok' res['update'] = 'ok'
else: else:
if (CagetteServices.registration_done(rid, overrided_date) is True): if (CagetteServices.registration_done(rid, overrided_date) is True):
res['update'] = 'ok' res['update'] = 'ok'
else: else:
...@@ -325,8 +326,8 @@ def easy_validate_shift_presence(request): ...@@ -325,8 +326,8 @@ def easy_validate_shift_presence(request):
else: else:
return JsonResponse(res, safe=False) return JsonResponse(res, safe=False)
def record_absences(request): def record_absences(request, date):
return JsonResponse({'res': CagetteServices.record_absences()}) return JsonResponse({'res': CagetteServices.record_absences(date)})
def close_ftop_service(request): def close_ftop_service(request):
"""Close the closest past FTOP service""" """Close the closest past FTOP service"""
......
...@@ -11,38 +11,37 @@ class CagetteMembersSpace(models.Model): ...@@ -11,38 +11,37 @@ class CagetteMembersSpace(models.Model):
"""Init with odoo id.""" """Init with odoo id."""
self.o_api = OdooAPI() self.o_api = OdooAPI()
def get_points_history(self, partner_id, limit, offset, date_from, shift_type): def get_shifts_history(self, partner_id, limit, offset, date_from):
""" Get partner points history with related shift registration if needed """ """ Get partner shifts history """
res = {}
today = str(datetime.date.today())
try:
cond = [ cond = [
['partner_id', '=', partner_id], ['partner_id', '=', partner_id],
['type', '=', shift_type],
['create_date', '>', date_from], ['create_date', '>', date_from],
['point_qty', '!=', 0] ['date_begin', '<', today],
['state', '!=', 'draft'],
['state', '!=', 'open'],
['state', '!=', 'waiting'],
['state', '!=', 'replaced'],
['state', '!=', 'replacing'],
] ]
f = ['create_date', 'create_uid', 'shift_id', 'name', 'point_qty'] f = ['create_date', 'shift_id', 'name', 'state', 'is_late', 'is_makeup']
res = self.o_api.search_read('shift.counter.event', cond, f, limit=limit, offset=offset, marshal_none_error = 'cannot marshal None unless allow_none is enabled'
try:
res = self.o_api.search_read('shift.registration', cond, f, limit=limit, offset=offset,
order='create_date DESC') order='create_date DESC')
except Exception as e:
# Get related data from shift.registration if not (marshal_none_error in str(e)):
shift_ids = [] res['error'] = repr(e)
for item in res: coop_logger.error(res['error'] + ' : %s', str(payment_id))
item['is_late'] = False # So every item has the attribute else:
res = []
if item['shift_id'] is not False:
shift_ids.append(item['shift_id'][0]) except Exception as e:
print(str(e))
cond = [['shift_id', 'in', shift_ids]]
f = ['is_late', 'shift_id']
res_shift_registration = self.o_api.search_read('shift.registration', cond, f)
for registration_item in res_shift_registration:
for shift_counter_item in res:
if (shift_counter_item['shift_id'] is not False
and shift_counter_item['shift_id'] == registration_item['shift_id']):
shift_counter_item['is_late'] = registration_item['is_late']
break
return res return res
\ No newline at end of file
...@@ -34,8 +34,15 @@ ...@@ -34,8 +34,15 @@
display: none; display: none;
} }
@media screen and (max-width: 768px) { .pairs_info {
/* When the screen is less than 768 pixels wide, hide all links, except for the first one ("Home"). Show the link that contains should open and close the topnav (.icon) */ background-color: #00a573;
color: white;
padding: 1.5rem 1.2rem;
display: none;
}
@media screen and (max-width: 992px) {
/* When the screen is less than 992 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:not(:first-child) {display: none;}
.topnav a.icon { .topnav a.icon {
float: right; float: right;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#my_info_content { #my_info_content {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
margin: 2rem 0;
} }
.my_info_line { .my_info_line {
...@@ -40,14 +41,13 @@ ...@@ -40,14 +41,13 @@
flex-direction: column; flex-direction: column;
} }
.pairs_info { .member_phone_area {
background-color: #00a573; display: flex;
color: white; flex-direction: column;
padding: 1.5rem 1.2rem; gap: 10px;
margin: 2rem 0;
} }
@media screen and (max-width: 768px) { @media screen and (max-width: 992px) {
#my_info { #my_info {
font-size: 1.7rem; font-size: 1.7rem;
} }
......
...@@ -35,7 +35,14 @@ table.dataTable.dtr-inline.collapsed>tbody>tr>th:first-child:before { ...@@ -35,7 +35,14 @@ table.dataTable.dtr-inline.collapsed>tbody>tr>th:first-child:before {
background-color: white; background-color: white;
font-weight: bold; font-weight: bold;
border: none; border: none;
font-size: 2rem; 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>td:first-child:before,
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th:first-child:before { table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th:first-child:before {
...@@ -43,7 +50,10 @@ table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th:first-child:before { ...@@ -43,7 +50,10 @@ table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th:first-child:before {
background-color: white; background-color: white;
font-weight: bold; font-weight: bold;
border: none; border: none;
font-size: 2rem;; font-size: 1.6rem;
height: 16px;
width: 16px;
border-radius: 2em;
} }
.loading-more-history { .loading-more-history {
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
text-align: center; text-align: center;
width: 50%; width: 50%;
} }
@media screen and (max-width:768px) { @media screen and (max-width:992px) {
#suspended_cant_have_delay_content { #suspended_cant_have_delay_content {
align-items: center; align-items: center;
text-align: center; text-align: center;
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
justify-content: space-between; justify-content: space-between;
} }
@media screen and (max-width:768px) { @media screen and (max-width:992px) {
#calendar_top_info { #calendar_top_info {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
...@@ -54,9 +54,10 @@ ...@@ -54,9 +54,10 @@
display: none; display: none;
width: min-content; width: min-content;
max-width: 100%; max-width: 100%;
white-space: nowrap;
} }
@media screen and (max-width:768px) { @media screen and (max-width:992px) {
#partner_shifts_list { #partner_shifts_list {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
...@@ -96,7 +97,7 @@ ...@@ -96,7 +97,7 @@
margin-right: 3px; margin-right: 3px;
} }
@media screen and (max-width:768px) { @media screen and (max-width:992px) {
.select_makeups_message_block { .select_makeups_message_block {
display: block; display: block;
} }
...@@ -113,7 +114,7 @@ ...@@ -113,7 +114,7 @@
display: none; display: none;
} }
@media screen and (max-width:768px) { @media screen and (max-width:992px) {
#calendar { #calendar {
display: none; display: none;
} }
...@@ -168,7 +169,7 @@ ...@@ -168,7 +169,7 @@
padding: 0 !important; padding: 0 !important;
} }
@media screen and (max-width:768px) { @media screen and (max-width:992px) {
.example-event { .example-event {
margin: 2rem auto 0.5rem auto; margin: 2rem auto 0.5rem auto;
} }
......
...@@ -13,6 +13,12 @@ body { ...@@ -13,6 +13,12 @@ body {
flex-wrap: wrap; flex-wrap: wrap;
} }
@media screen and (max-width: 992px) {
.tiles_container {
flex-direction: column;
}
}
.tile { .tile {
flex: 1 0 45%; flex: 1 0 45%;
display: flex; display: flex;
...@@ -39,15 +45,10 @@ body { ...@@ -39,15 +45,10 @@ body {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
border-bottom: 1px solid #e7e9ed; border-bottom: 1px solid #e7e9ed;
font-size: 2.7rem; font-size: 2.4rem;
padding: 2rem 0; padding: 2rem 0;
width: 80%; width: 80%;
} }
@media screen and (max-width: 768px) {
.tile_title {
font-size: 2.5rem;
}
}
.tile_content { .tile_content {
position: relative; position: relative;
...@@ -58,7 +59,11 @@ body { ...@@ -58,7 +59,11 @@ body {
} }
#home_tile_services_exchange .tile_content { #home_tile_services_exchange .tile_content {
justify-content: center; height: 100%;
flex-direction: column;
align-items: center;
text-align: center;
} }
...@@ -109,6 +114,10 @@ body { ...@@ -109,6 +114,10 @@ body {
position: relative; position: relative;
} }
#home_tile_my_info .tile_content {
margin: 2rem 0;
}
.tile_icon { .tile_icon {
margin-right: 15px; margin-right: 15px;
color: #00a573; color: #00a573;
...@@ -118,11 +127,17 @@ body { ...@@ -118,11 +127,17 @@ body {
height: 100%; height: 100%;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
font-size: 2.2rem; font-size: 2rem;
} }
@media screen and (max-width: 768px) { @media screen and (max-width: 992px) {
#home_tile_my_info .tile_content { #home_tile_my_info .tile_content {
font-size: 1.9rem; font-size: 1.7rem;
}
}
@media screen and (max-width: 380px) {
#home_tile_my_info .tile_content {
font-size: 1.6rem !important;
} }
} }
...@@ -130,24 +145,29 @@ body { ...@@ -130,24 +145,29 @@ body {
font-weight: bold; font-weight: bold;
} }
.member_status_text_container {
margin-bottom: 5px;
}
#member_status_action { #member_status_action {
margin-bottom: 20px; margin-bottom: 20px;
} }
@media screen and (max-width: 768px) { @media screen and (max-width: 992px) {
#member_status_action { #member_status_action {
margin-top: 5px;
margin-bottom: 10px; margin-bottom: 10px;
} }
} }
.choose_makeups { .choose_makeups {
display: none; display: none;
font-size: 1.8rem; font-size: 1.5rem;
} }
.unsuscribed_form_link { .unsuscribed_form_link {
display: none; display: none;
text-decoration: none; text-decoration: none;
font-size: 1.7rem; font-size: 1.5rem;
} }
.unsuscribed_form_link:hover { .unsuscribed_form_link:hover {
text-decoration: none; text-decoration: none;
...@@ -167,17 +187,38 @@ body { ...@@ -167,17 +187,38 @@ body {
color: #d9534f; color: #d9534f;
} }
.member_shift_name_area {
margin-top: 10px;
}
.member_shift_name_area, .member_shift_name_area,
.member_coop_number_area { .member_coop_number_area {
margin-bottom: 10px; margin-bottom: 10px;
} }
@media screen and (max-width: 768px) { .member_shift_name_area,
.member_coop_number_area,
.member_associated_partner_area {
font-size: 1.9rem;
line-height: 1.3;
}
@media screen and (max-width: 380px) {
.member_shift_name_area, .member_shift_name_area,
.member_coop_number_area { .member_coop_number_area,
.member_associated_partner_area {
font-size: 1.6rem;
}
}
@media screen and (max-width: 992px) {
.member_shift_name_area,
.member_coop_number_area,
.member_associated_partner_area {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
font-size: 1.7rem;
} }
} }
...@@ -268,7 +309,7 @@ body { ...@@ -268,7 +309,7 @@ body {
} }
} }
@media screen and (max-width: 768px) { @media screen and (max-width: 992px) {
#shop_info_content { #shop_info_content {
flex-direction: column; flex-direction: column;
} }
......
...@@ -47,4 +47,8 @@ $(document).ready(function() { ...@@ -47,4 +47,8 @@ $(document).ready(function() {
$('#nav_calendar').on('click', () => { $('#nav_calendar').on('click', () => {
toggleHeader(); toggleHeader();
}); });
if (partner_data.is_associated_people === "True") {
$(".pairs_info").show();
}
}); });
...@@ -25,7 +25,7 @@ function request_delay() { ...@@ -25,7 +25,7 @@ function request_delay() {
}, },
success: function() { success: function() {
partner_data.cooperative_state = 'delay'; partner_data.cooperative_state = 'delay';
partner_data.date_delay_stop = today.getFullYear()+'-'+(today.getMonth()+1)+'-'+today.getDate(); partner_data.date_delay_stop = today_plus_six_month.getFullYear()+'-'+(today_plus_six_month.getMonth()+1)+'-'+today_plus_six_month.getDate();
resolve(); resolve();
}, },
...@@ -97,6 +97,18 @@ function init_home() { ...@@ -97,6 +97,18 @@ function init_home() {
}); });
$("#go_to_forms").prop("href", forms_link); $("#go_to_forms").prop("href", forms_link);
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 tile
init_my_info_data(); init_my_info_data();
......
...@@ -3,10 +3,14 @@ function init_my_info() { ...@@ -3,10 +3,14 @@ function init_my_info() {
$(".member_email").text(partner_data.email); $(".member_email").text(partner_data.email);
if (partner_data.is_associated_people === "False") { if (partner_data.is_in_association === false) {
$("#attached_info_area").hide(); $("#attached_info_area").hide();
} else { }
if (partner_data.is_associated_people === "True") {
$(".attached_partner_name").text(partner_data.parent_name); $(".attached_partner_name").text(partner_data.parent_name);
} else if (partner_data.associated_partner_id !== "False") {
$(".attached_partner_name").text(partner_data.associated_partner_name);
} }
if (partner_data.street !== "") { if (partner_data.street !== "") {
...@@ -22,17 +26,22 @@ function init_my_info() { ...@@ -22,17 +26,22 @@ function init_my_info() {
$(".member_address_line").hide(); $(".member_address_line").hide();
} }
if (partner_data.mobile !== "") {
if (partner_data.mobile !== "" && partner_data.mobile !== "False" && partner_data.mobile !== false && partner_data.mobile !== null) {
$(".member_mobile") $(".member_mobile")
.append(partner_data.mobile); .append(partner_data.mobile);
} else { } else {
$(".member_mobile_line").hide(); $(".member_mobile").hide();
} }
if (partner_data.phone !== "") { if (partner_data.phone !== "" && partner_data.phone !== "False" && partner_data.phone !== false && partner_data.phone !== null) {
$(".member_phone") $(".member_phone")
.append(partner_data.phone); .append(partner_data.phone);
} else { } else {
$(".member_phone").hide();
}
if ($(".member_mobile").text() === "" && $(".member_phone").text() === "") {
$(".member_phone_line").hide(); $(".member_phone_line").hide();
} }
} }
\ No newline at end of file
...@@ -9,13 +9,12 @@ function load_partner_history(offset = 0) { ...@@ -9,13 +9,12 @@ function load_partner_history(offset = 0) {
return new Promise((resolve) => { return new Promise((resolve) => {
$.ajax({ $.ajax({
type: 'GET', type: 'GET',
url: "/members_space/get_points_history", url: "/members_space/get_shifts_history",
data: { data: {
partner_id: partner_data.concerned_partner_id, partner_id: partner_data.concerned_partner_id,
verif_token: partner_data.verif_token, verif_token: partner_data.verif_token,
limit: history_items_limit, limit: history_items_limit,
offset: offset, offset: offset
shift_type: (partner_data.in_ftop_team === "True") ? "ftop" : "standard"
}, },
dataType:"json", dataType:"json",
traditional: true, traditional: true,
...@@ -49,36 +48,18 @@ function prepare_server_data(data) { ...@@ -49,36 +48,18 @@ function prepare_server_data(data) {
res = []; res = [];
for (history_item of data) { for (history_item of data) {
// Date formating history_item.details = '';
let datetime_shift_start = new Date(history_item.create_date); if (history_item.state === 'excused' || history_item.state === 'absent') {
history_item.details = "Absent";
let f_date_shift_start = datetime_shift_start.toLocaleDateString("fr-fr", date_options); } else if (history_item.state === 'done' && history_item.is_late != false) {
history_item.details = "Présent (En Retard)";
f_date_shift_start = f_date_shift_start.charAt(0).toUpperCase() + f_date_shift_start.slice(1); } else if (history_item.state === 'done') {
history_item.details = "Présent";
history_item.movement_date = f_date_shift_start + " - " + datetime_shift_start.toLocaleTimeString("fr-fr", time_options); } else if (history_item.state === 'cancel') {
history_item.details = "Annulé";
// Text replacements
history_item.name = (history_item.name === "Clôturer le service") ? "Décompte 28j" : history_item.name;//Clôlturer le service
history_item.name = (history_item.name === "Rattrapage") ? "Absence" : history_item.name;
if (history_item.name === "Clôturer le service" || history_item.name === "Clôlturer le service") {
history_item.name = "Décompte 28j";
} else if (history_item.name === "Rattrapage") {
history_item.name = "Absence";
} else if (history_item.name === "Présent" && history_item.is_late != false) {
history_item.name = "Retard";
}
history_item.created_by = history_item.create_uid[1];
if (history_item.created_by === "Administrator") {
history_item.created_by = "Administrateur";
} else if (history_item.created_by === "api") {
history_item.created_by = "Système";
} }
history_item.shift_name = (history_item.shift_id === false) ? '' : history_item.shift_id[1]; history_item.shift_name = (history_item.shift_id === false) ? '' : history_item.shift_id[1];
// if Present && is_late -> Absent
} }
return data; return data;
...@@ -99,18 +80,14 @@ function init_history() { ...@@ -99,18 +80,14 @@ function init_history() {
data: partner_history, data: partner_history,
columns: [ columns: [
{ {
data: "movement_date",
title: `Date`,
responsivePriority: 1
},
{
data: "shift_name", data: "shift_name",
title: "Service" title: "<spans class='dt-body-center'>Service</span>",
width: "60%"
}, },
{ {
data: "name", data: "details",
title: "Détails", title: "Détails",
responsivePriority: 3 className: "tablet-l desktop"
} }
], ],
iDisplayLength: -1, iDisplayLength: -1,
...@@ -126,7 +103,7 @@ function init_history() { ...@@ -126,7 +103,7 @@ function init_history() {
$(row).addClass('row_partner_ok'); $(row).addClass('row_partner_ok');
} else if (cell.text() === "Retard") { } else if (cell.text() === "Retard") {
$(row).addClass('row_partner_late'); $(row).addClass('row_partner_late');
} else if (cell.text() === "Absence") { } else if (cell.text() === "Absent") {
$(row).addClass('row_partner_absent'); $(row).addClass('row_partner_absent');
} }
} }
......
...@@ -32,7 +32,7 @@ function add_or_change_shift(new_shift_id) { ...@@ -32,7 +32,7 @@ function add_or_change_shift(new_shift_id) {
tData = 'idNewShift=' + new_shift_id tData = 'idNewShift=' + new_shift_id
+'&idPartner=' + partner_data.partner_id +'&idPartner=' + partner_data.partner_id
+ '&in_ftop_team=' + partner_data.in_ftop_team + '&shift_type=' + partner_data.shift_type
+ '&verif_token=' + partner_data.verif_token; + '&verif_token=' + partner_data.verif_token;
if (selected_shift === null) { if (selected_shift === null) {
......
...@@ -15,7 +15,7 @@ const possible_cooperative_state = { ...@@ -15,7 +15,7 @@ const possible_cooperative_state = {
exempted: "Exempté.e", exempted: "Exempté.e",
alert: "En alerte", alert: "En alerte",
up_to_date: "À jour", up_to_date: "À jour",
unsubscribed: "Désinscrit.e", unsubscribed: "Désinscrit.e des créneaux",
delay: "En délai" delay: "En délai"
}; };
...@@ -68,6 +68,10 @@ function goto(page) { ...@@ -68,6 +68,10 @@ function goto(page) {
/** /**
* Define which html content to load from server depending on the window location * 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() { function update_dom() {
$(".nav_item").removeClass('active'); $(".nav_item").removeClass('active');
...@@ -150,6 +154,11 @@ function init_my_info_data() { ...@@ -150,6 +154,11 @@ function init_my_info_data() {
$(".member_shift_name").text(partner_data.regular_shift_name); $(".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 // Status related
$(".member_status") $(".member_status")
.text(possible_cooperative_state[partner_data.cooperative_state]) .text(possible_cooperative_state[partner_data.cooperative_state])
...@@ -214,6 +223,14 @@ $(document).ready(function() { ...@@ -214,6 +223,14 @@ $(document).ready(function() {
? partner_data.parent_id ? partner_data.parent_id
: partner_data.partner_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/' : '/'; base_location = (app_env === 'dev') ? '/members_space/' : '/';
update_dom(); update_dom();
......
...@@ -5,11 +5,11 @@ from . import views ...@@ -5,11 +5,11 @@ from . import views
urlpatterns = [ urlpatterns = [
url(r'^$', views.index), url(r'^$', views.index),
url(r'^homepage$', views.home), url(r'^homepage$', views.home), # These endpoints must be different than in-app url
url(r'^my_info$', views.my_info), url(r'^my_info$', views.my_info),
url(r'^my_shifts$', views.my_shifts), url(r'^my_shifts$', views.my_shifts),
url(r'^shifts_exchange$', views.shifts_exchange), url(r'^shifts_exchange$', views.shifts_exchange),
url(r'^no_content$', views.no_content), url(r'^no_content$', views.no_content),
url(r'^get_points_history$', views.get_points_history), url(r'^get_shifts_history$', views.get_shifts_history),
url('/*$', views.index), url('/*$', views.index), # Urls unknown from the server will redirect to index
] ]
...@@ -39,6 +39,7 @@ def index(request, exception=None): ...@@ -39,6 +39,7 @@ def index(request, exception=None):
if 'msg' in credentials: if 'msg' in credentials:
context['msg'] = credentials['msg'] context['msg'] = credentials['msg']
context['password_placeholder'] = 'Naissance (jjmmaaaa)' context['password_placeholder'] = 'Naissance (jjmmaaaa)'
context['is_member_space'] = True
elif ('validation_state' in credentials) and credentials['validation_state'] == 'waiting_validation_member': elif ('validation_state' in credentials) and credentials['validation_state'] == 'waiting_validation_member':
# First connection, until the member validated his account # First connection, until the member validated his account
template = loader.get_template('members/validation_coop.html') template = loader.get_template('members/validation_coop.html')
...@@ -76,6 +77,7 @@ def index(request, exception=None): ...@@ -76,6 +77,7 @@ def index(request, exception=None):
partner_id = credentials['id'] partner_id = credentials['id']
cs = CagetteShift() cs = CagetteShift()
partnerData = cs.get_data_partner(partner_id) partnerData = cs.get_data_partner(partner_id)
if 'create_date' in partnerData: if 'create_date' in partnerData:
...@@ -89,12 +91,23 @@ def index(request, exception=None): ...@@ -89,12 +91,23 @@ def index(request, exception=None):
except: except:
pass pass
# look for parent for associated partner
if partnerData["parent_id"] is not False: if partnerData["parent_id"] is not False:
partnerData["parent_name"] = partnerData["parent_id"][1] partnerData["parent_name"] = partnerData["parent_id"][1]
partnerData["parent_id"] = partnerData["parent_id"][0] partnerData["parent_id"] = partnerData["parent_id"][0]
else: else:
partnerData["parent_name"] = False partnerData["parent_name"] = False
# look for associated partner for parents
cm = CagetteMember(partner_id)
associated_partner = cm.search_associated_people()
partnerData["associated_partner_id"] = False if associated_partner is None else associated_partner["id"]
partnerData["associated_partner_name"] = False if associated_partner is None else associated_partner["name"]
if (associated_partner is not None and partnerData["associated_partner_name"].find(str(associated_partner["barcode_base"])) == -1):
partnerData["associated_partner_name"] = str(associated_partner["barcode_base"]) + ' - ' + partnerData["associated_partner_name"]
partnerData['can_have_delay'] = cs.member_can_have_delay(int(partner_id)) partnerData['can_have_delay'] = cs.member_can_have_delay(int(partner_id))
context['partnerData'] = partnerData context['partnerData'] = partnerData
...@@ -125,6 +138,12 @@ def index(request, exception=None): ...@@ -125,6 +138,12 @@ def index(request, exception=None):
return _get_response_according_to_credentials(request, credentials, context, template) return _get_response_according_to_credentials(request, credentials, context, template)
def home(request): def home(request):
"""
Endpoint the front-end will call to load the "home" page.
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('members_space/home.html')
context = { context = {
'title': 'Espace Membres', 'title': 'Espace Membres',
...@@ -138,6 +157,7 @@ def home(request): ...@@ -138,6 +157,7 @@ def home(request):
return HttpResponse(template.render(context, request)) return HttpResponse(template.render(context, request))
def my_info(request): def my_info(request):
""" Endpoint the front-end will call to load the "My info" page. """
template = loader.get_template('members_space/my_info.html') template = loader.get_template('members_space/my_info.html')
context = { context = {
'title': 'Mes Infos', 'title': 'Mes Infos',
...@@ -145,6 +165,7 @@ def my_info(request): ...@@ -145,6 +165,7 @@ def my_info(request):
return HttpResponse(template.render(context, request)) return HttpResponse(template.render(context, request))
def my_shifts(request): def my_shifts(request):
""" Endpoint the front-end will call to load the "My shifts" page. """
template = loader.get_template('members_space/my_shifts.html') template = loader.get_template('members_space/my_shifts.html')
context = { context = {
'title': 'Mes Services', 'title': 'Mes Services',
...@@ -152,6 +173,7 @@ def my_shifts(request): ...@@ -152,6 +173,7 @@ def my_shifts(request):
return HttpResponse(template.render(context, request)) return HttpResponse(template.render(context, request))
def shifts_exchange(request): def shifts_exchange(request):
""" Endpoint the front-end will call to load the "Shifts exchange" page. """
template = loader.get_template('members_space/shifts_exchange.html') template = loader.get_template('members_space/shifts_exchange.html')
context = { context = {
'title': 'Échange de Services', 'title': 'Échange de Services',
...@@ -159,13 +181,14 @@ def shifts_exchange(request): ...@@ -159,13 +181,14 @@ def shifts_exchange(request):
return HttpResponse(template.render(context, request)) return HttpResponse(template.render(context, request))
def no_content(request): def no_content(request):
""" Endpoint the front-end will call to load the "No content" page. """
template = loader.get_template('members_space/no_content.html') template = loader.get_template('members_space/no_content.html')
context = { context = {
'title': 'Contenu non trouvé', 'title': 'Contenu non trouvé',
} }
return HttpResponse(template.render(context, request)) return HttpResponse(template.render(context, request))
def get_points_history(request): def get_shifts_history(request):
res = {} res = {}
partner_id = int(request.GET.get('partner_id')) partner_id = int(request.GET.get('partner_id'))
...@@ -173,8 +196,7 @@ def get_points_history(request): ...@@ -173,8 +196,7 @@ def get_points_history(request):
limit = int(request.GET.get('limit')) limit = int(request.GET.get('limit'))
offset = int(request.GET.get('offset')) offset = int(request.GET.get('offset'))
shift_type = request.GET.get('shift_type') date_from = getattr(settings, 'START_DATE_FOR_SHIFTS_HISTORY', '2018-01-01')
date_from = getattr(settings, 'START_DATE_FOR_POINTS_HISTORY', '2018-01-01') res["data"] = m.get_shifts_history(partner_id, limit, offset, date_from)
res["data"] = m.get_points_history(partner_id, limit, offset, date_from, shift_type)
return JsonResponse(res) return JsonResponse(res)
\ No newline at end of file
...@@ -264,6 +264,15 @@ ...@@ -264,6 +264,15 @@
(if not set, 60 minutes is the default) (if not set, 60 minutes is the default)
- ENTRANCE_VALIDATE_PRESENCE_MESSAGE = """
<div class="explanations">
Ta présence a bien été validée ! Merci de te diriger au fond du magasin pour le lancement du créneau !
</div>
Ton prochain service <span class="service_verb">est prévu</span> le <span class="next_shift"></span>
"""
(La Cagette message, where no point data is displayed)
### Member space ### Member space
- EM_URL = '' - EM_URL = ''
...@@ -352,7 +361,7 @@ ...@@ -352,7 +361,7 @@
Should be set to False by default if parameter not set Should be set to False by default if parameter not set
- START_DATE_FOR_POINTS_HISTORY = "2018-01-01" - START_DATE_FOR_SHIFTS_HISTORY = "2018-01-01"
......
...@@ -21,5 +21,7 @@ def custom_css(request): ...@@ -21,5 +21,7 @@ def custom_css(request):
def context_setting(request): def context_setting(request):
"""adding settings variable to context (can be overloaded in views).""" """adding settings variable to context (can be overloaded in views)."""
context = {'odoo': settings.ODOO['url'], 'app_env': getattr(settings, 'APP_ENV', "prod") } context = {'odoo': settings.ODOO['url'],
'app_env': getattr(settings, 'APP_ENV', "prod"),
'company_code': getattr(settings, 'COMPANY_CODE', '')}
return context return context
\ No newline at end of file
...@@ -36,7 +36,7 @@ class CagetteShift(models.Model): ...@@ -36,7 +36,7 @@ class CagetteShift(models.Model):
fields = ['display_name', 'display_std_points', fields = ['display_name', 'display_std_points',
'shift_type', 'date_alert_stop', 'date_delay_stop', 'extension_ids', 'shift_type', 'date_alert_stop', 'date_delay_stop', 'extension_ids',
'cooperative_state', 'final_standard_point', 'create_date', 'cooperative_state', 'final_standard_point', 'create_date',
'final_ftop_point', 'in_ftop_team', 'leave_ids', 'makeups_to_do', 'barcode_base', 'final_ftop_point', 'shift_type', 'leave_ids', 'makeups_to_do', 'barcode_base',
'street', 'street2 ,' 'zip', 'city', 'mobile', 'phone', 'email', 'street', 'street2 ,' 'zip', 'city', 'mobile', 'phone', 'email',
'is_associated_people', 'parent_id'] 'is_associated_people', 'parent_id']
partnerData = self.o_api.search_read('res.partner', cond, fields, 1) partnerData = self.o_api.search_read('res.partner', cond, fields, 1)
...@@ -89,6 +89,15 @@ class CagetteShift(models.Model): ...@@ -89,6 +89,15 @@ class CagetteShift(models.Model):
shiftData = self.o_api.search_read('shift.registration', cond, fields, order ="date_begin ASC") shiftData = self.o_api.search_read('shift.registration', cond, fields, order ="date_begin ASC")
return shiftData return shiftData
def shift_is_makeup(self, id):
"""vérifie si une shift est un rattrapage"""
fields = ["is_makeup", "id"]
cond = [['id', '=', id]]
shiftData = self.o_api.search_read('shift.registration', cond, fields)
return shiftData[0]["is_makeup"]
def get_shift_calendar(self, id, start, end): def get_shift_calendar(self, id, start, end):
"""Récupère les shifts à partir de maintenant pour le calendier""" """Récupère les shifts à partir de maintenant pour le calendier"""
cond = [['date_begin', '>', datetime.datetime.now().isoformat()], cond = [['date_begin', '>', datetime.datetime.now().isoformat()],
...@@ -120,14 +129,14 @@ class CagetteShift(models.Model): ...@@ -120,14 +129,14 @@ class CagetteShift(models.Model):
fields = ['stop_date', 'id', 'start_date'] fields = ['stop_date', 'id', 'start_date']
return self.o_api.search_read('shift.leave', cond, fields) return self.o_api.search_read('shift.leave', cond, fields)
def get_shift_ticket(self,idShift, in_ftop_team): def get_shift_ticket(self,idShift, shift_type):
"""Récupérer le shift_ticket suivant le membre et flotant ou pas""" """Récupérer le shift_ticket suivant le membre et flotant ou pas"""
if getattr(settings, 'USE_STANDARD_SHIFT', True) == False: if getattr(settings, 'USE_STANDARD_SHIFT', True) == False:
in_ftop_team = "True" shift_type = "ftop"
fields = ['shift_ticket_ids'] fields = ['shift_ticket_ids']
cond = [['id', "=", idShift]] cond = [['id', "=", idShift]]
listeTicket = self.o_api.search_read('shift.shift', cond, fields) listeTicket = self.o_api.search_read('shift.shift', cond, fields)
if in_ftop_team == "True": if shift_type == "ftop":
return listeTicket[0]['shift_ticket_ids'][1] return listeTicket[0]['shift_ticket_ids'][1]
else: else:
return listeTicket[0]['shift_ticket_ids'][0] return listeTicket[0]['shift_ticket_ids'][0]
...@@ -137,13 +146,14 @@ class CagetteShift(models.Model): ...@@ -137,13 +146,14 @@ class CagetteShift(models.Model):
st_r_id = False st_r_id = False
try: try:
shift_type = "standard" shift_type = "standard"
if data['in_ftop_team'] == "True" or getattr(settings, 'USE_STANDARD_SHIFT', True) == False: if data['shift_type'] == "ftop" or getattr(settings, 'USE_STANDARD_SHIFT', True) == False:
shift_type = "ftop" shift_type = "ftop"
fieldsDatas = { "partner_id": data['idPartner'], fieldsDatas = { "partner_id": data['idPartner'],
"shift_id": data['idShift'], "shift_id": data['idShift'],
"shift_ticket_id": self.get_shift_ticket(data['idShift'], data['in_ftop_team']), "shift_ticket_id": self.get_shift_ticket(data['idShift'], data['shift_type']),
"shift_type": shift_type, "shift_type": shift_type,
"origin": 'memberspace', "origin": 'memberspace',
"is_makeup": data['is_makeup'],
"state": 'open'} "state": 'open'}
st_r_id = self.o_api.create('shift.registration', fieldsDatas) st_r_id = self.o_api.create('shift.registration', fieldsDatas)
......
...@@ -57,7 +57,7 @@ function loadShiftPartner(partner_id) { ...@@ -57,7 +57,7 @@ function loadShiftPartner(partner_id) {
$('#shift_msg').remove(); $('#shift_msg').remove();
$('#partnerData').append('<div id="shift_msg"></div>'); $('#partnerData').append('<div id="shift_msg"></div>');
if (dataPartner.in_ftop_team == "True" || listeShiftPartner.length > 0) { if (dataPartner.shift_type == "ftop" || listeShiftPartner.length > 0) {
// ftop, no shift planned // ftop, no shift planned
if (listeShiftPartner.length == 0) { if (listeShiftPartner.length == 0) {
var date = new Date(dataPartner.next_regular_shift_date); var date = new Date(dataPartner.next_regular_shift_date);
...@@ -79,7 +79,7 @@ function loadShiftPartner(partner_id) { ...@@ -79,7 +79,7 @@ function loadShiftPartner(partner_id) {
// Set DOM for partner's shifts and shift message for ftops // Set DOM for partner's shifts and shift message for ftops
iniListShift(listeShiftPartner, true); iniListShift(listeShiftPartner, true);
if (dataPartner.in_ftop_team == "True") { if (dataPartner.shift_type == "ftop") {
$('#shift_msg').append("<br /><strong>Je peux choisir d'autres services pour les mois à venir ou échanger un de ceux de la liste.</strong>"); $('#shift_msg').append("<br /><strong>Je peux choisir d'autres services pour les mois à venir ou échanger un de ceux de la liste.</strong>");
} }
} }
...@@ -92,7 +92,7 @@ function changeShift(idOldRegister, idNewShift) { ...@@ -92,7 +92,7 @@ function changeShift(idOldRegister, idNewShift) {
if (is_time_to('change_shift')) { if (is_time_to('change_shift')) {
openModal(); // loading on openModal(); // loading on
tData = 'idNewShift=' + idNewShift +'&idPartner=' + dataPartner.partner_id + '&in_ftop_team=' + dataPartner.in_ftop_team + '&verif_token=' + dataPartner.verif_token; tData = 'idNewShift=' + idNewShift +'&idPartner=' + dataPartner.partner_id + '&shift_type=' + dataPartner.shift_type + '&verif_token=' + dataPartner.verif_token;
if (idOldRegister == "") { if (idOldRegister == "") {
tUrl = '/shifts/add_shift'; tUrl = '/shifts/add_shift';
} else { } else {
...@@ -161,7 +161,7 @@ function canMakeExchange() { ...@@ -161,7 +161,7 @@ function canMakeExchange() {
var answer = false; var answer = false;
// Set the partner's limit date (after which he'll loose a point) // Set the partner's limit date (after which he'll loose a point)
if (dataPartner.dateProlonge != "False" || dataPartner.final_standard_point < 0 || dataPartner.in_ftop_team == "True") { if (dataPartner.dateProlonge != "False" || dataPartner.final_standard_point < 0 || dataPartner.shift_type == "ftop") {
var dateProlonge = new Date(dataPartner.dateProlonge); var dateProlonge = new Date(dataPartner.dateProlonge);
var dateNextRegularShift = new Date(dataPartner.next_regular_shift_date); var dateNextRegularShift = new Date(dataPartner.next_regular_shift_date);
...@@ -170,7 +170,7 @@ function canMakeExchange() { ...@@ -170,7 +170,7 @@ function canMakeExchange() {
// For ABCD : the limit date is end of alert // For ABCD : the limit date is end of alert
var dateEndAlert = new Date(dataPartner.date_alert_stop); var dateEndAlert = new Date(dataPartner.date_alert_stop);
if (dataPartner.in_ftop_team == "False" && limitDate < dateEndAlert) { if (dataPartner.shift_type == "ftop" && limitDate < dateEndAlert) {
limitDate = dateEndAlert; limitDate = dateEndAlert;
} }
...@@ -204,7 +204,7 @@ function canMakeExchange() { ...@@ -204,7 +204,7 @@ function canMakeExchange() {
}); });
// Allow exchange if points >= 0 or he already has enough services booked before the limit date // Allow exchange if points >= 0 or he already has enough services booked before the limit date
var partner_points = dataPartner.in_ftop_team == "True" ? dataPartner.final_ftop_point : dataPartner.final_standard_point; var partner_points = dataPartner.shift_type == "ftop" ? dataPartner.final_ftop_point : dataPartner.final_standard_point;
if (partner_points >= 0 || shifts_before_limit >= 1) { if (partner_points >= 0 || shifts_before_limit >= 1) {
answer = true; answer = true;
...@@ -216,7 +216,7 @@ function canMakeExchange() { ...@@ -216,7 +216,7 @@ function canMakeExchange() {
} }
// ftop can always exchange service // ftop can always exchange service
if (dataPartner.in_ftop_team == "True") { if (dataPartner.shift_type == "ftop") {
answer = true; answer = true;
} }
} }
...@@ -230,7 +230,7 @@ Génère le message à afficher lorsque le coop doit faire un rattrapage. ...@@ -230,7 +230,7 @@ Génère le message à afficher lorsque le coop doit faire un rattrapage.
Pour les volants, chaque service compte comme un rattrapage. Pour les volants, chaque service compte comme un rattrapage.
*/ */
function addMakeUpMsg() { function addMakeUpMsg() {
var partner_points = dataPartner.in_ftop_team == "True" ? dataPartner.final_ftop_point : dataPartner.final_standard_point; var partner_points = dataPartner.shift_type == "ftop" ? dataPartner.final_ftop_point : dataPartner.final_standard_point;
let shifts_before_limit = 0; let shifts_before_limit = 0;
// Calcul du nombre de rattrapages à faire // Calcul du nombre de rattrapages à faire
...@@ -281,7 +281,7 @@ function addMakeUpMsg() { ...@@ -281,7 +281,7 @@ function addMakeUpMsg() {
} }
// Si le membre est un volant // Si le membre est un volant
if (dataPartner.in_ftop_team == "True") { if (dataPartner.shift_type == "ftop") {
msg = "Je dois faire " + make_up_nb + " service"; msg = "Je dois faire " + make_up_nb + " service";
if (make_up_nb > 1) msg += "s"; if (make_up_nb > 1) msg += "s";
if (non_regular_shifts.length > 0) msg += " en plus"; if (non_regular_shifts.length > 0) msg += " en plus";
...@@ -320,7 +320,7 @@ function canAddShift(date_new_shift) { ...@@ -320,7 +320,7 @@ function canAddShift(date_new_shift) {
var answer = false; var answer = false;
// If partner is ftop (ftop = volant) // If partner is ftop (ftop = volant)
if (dataPartner["in_ftop_team"] == "True") { if (dataPartner["shift_type"] == "ftop") {
// If points >= 0 : can register to any shift // If points >= 0 : can register to any shift
if (dataPartner.final_ftop_point >= 0) { if (dataPartner.final_ftop_point >= 0) {
answer = true; answer = true;
...@@ -414,7 +414,7 @@ $(document).ready(function() { ...@@ -414,7 +414,7 @@ $(document).ready(function() {
loadShiftPartner(dataPartner.partner_id); loadShiftPartner(dataPartner.partner_id);
// Display information depending on partner's type and state // Display information depending on partner's type and state
if (dataPartner.in_ftop_team == "True") { if (dataPartner.shift_type == "ftop") {
$('div.intro div h2').text("Bienvenue dans le système de choix et d'échange de services"); $('div.intro div h2').text("Bienvenue dans le système de choix et d'échange de services");
$('.additionnal_intro_data').text(' ou en choisir un nouveau'); $('.additionnal_intro_data').text(' ou en choisir un nouveau');
...@@ -543,7 +543,7 @@ $(document).ready(function() { ...@@ -543,7 +543,7 @@ $(document).ready(function() {
// For partners who can't add a shift as it is // For partners who can't add a shift as it is
if (!can_add_shift) { if (!can_add_shift) {
// Partners who could ask for a delay // Partners who could ask for a delay
if (dataPartner.in_ftop_team == "True" || dataPartner.in_ftop_team == "False" && dateShiftNew > limitDate) { if (dataPartner.shift_type == "ftop" || dateShiftNew > limitDate) {
// Member can ask for 6 delays, which is 24 weeks after entering alert status // Member can ask for 6 delays, which is 24 weeks after entering alert status
// 'date_alert_stop' field is begining of alert + 4 weeks // 'date_alert_stop' field is begining of alert + 4 weeks
let date_end_alert = new Date(dataPartner.date_alert_stop); let date_end_alert = new Date(dataPartner.date_alert_stop);
......
...@@ -178,10 +178,12 @@ def change_shift(request): ...@@ -178,10 +178,12 @@ def change_shift(request):
if 'idNewShift' in request.POST and 'idOldShift' in request.POST: if 'idNewShift' in request.POST and 'idOldShift' in request.POST:
idOldShift = request.POST['idOldShift'] idOldShift = request.POST['idOldShift']
listRegister = [int(request.POST['idRegister'])]
data = { data = {
"idPartner": int(request.POST['idPartner']), "idPartner": int(request.POST['idPartner']),
"idShift":int(request.POST['idNewShift']), "idShift": int(request.POST['idNewShift']),
"in_ftop_team":request.POST['in_ftop_team'] "shift_type": request.POST['shift_type'],
"is_makeup": cs.shift_is_makeup(idOldShift)
} }
should_block_service_exchange = getattr(settings, 'BLOCK_SERVICE_EXCHANGE_24H_BEFORE', False) should_block_service_exchange = getattr(settings, 'BLOCK_SERVICE_EXCHANGE_24H_BEFORE', False)
...@@ -228,7 +230,8 @@ def add_shift(request): ...@@ -228,7 +230,8 @@ def add_shift(request):
data = { data = {
"idPartner": int(request.POST['idPartner']), "idPartner": int(request.POST['idPartner']),
"idShift":int(request.POST['idNewShift']), "idShift":int(request.POST['idNewShift']),
"in_ftop_team":request.POST['in_ftop_team'] "shift_type":request.POST['shift_type'],
"is_makeup":True
} }
#Insertion du nouveau shift #Insertion du nouveau shift
......
...@@ -188,6 +188,9 @@ ...@@ -188,6 +188,9 @@
<h1 class="col-6 txtcenter">Bon service !</h1> <h1 class="col-6 txtcenter">Bon service !</h1>
<section class="col-6 txtcenter"> <section class="col-6 txtcenter">
<span class="member_name"></span><br /> <span class="member_name"></span><br />
{% if ENTRANCE_VALIDATE_PRESENCE_MESSAGE != '' %}
{{ENTRANCE_VALIDATE_PRESENCE_MESSAGE|safe}}
{% else %}
Votre présence est bien enregistrée ! <br /> Votre présence est bien enregistrée ! <br />
<div class="compteur"> <div class="compteur">
Votre compteur est dorénavant à <span class="points"></span> point(s).<br /> Votre compteur est dorénavant à <span class="points"></span> point(s).<br />
...@@ -200,6 +203,7 @@ ...@@ -200,6 +203,7 @@
</div> </div>
</div> </div>
Votre prochain service <span class="service_verb">est prévu</span> le <span class="next_shift"></span> Votre prochain service <span class="service_verb">est prévu</span> le <span class="next_shift"></span>
{% endif %}
</section> </section>
<div class="col-2"></div> <div class="col-2"></div>
<a class="btn col-2" data-next="first_page">Coopérateur suivant</a> <a class="btn col-2" data-next="first_page">Coopérateur suivant</a>
......
...@@ -24,6 +24,14 @@ ...@@ -24,6 +24,14 @@
<i class="fa fa-bars"></i> <i class="fa fa-bars"></i>
</a> </a>
</div> </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> <script type="text/javascript" src="{% static 'js/members-space-header.js' %}"></script>
{% endblock %} {% endblock %}
...@@ -6,10 +6,11 @@ ...@@ -6,10 +6,11 @@
<div class="tile high_tile" id="home_tile_my_info"> <div class="tile high_tile" id="home_tile_my_info">
<div class="tile_title"> <div class="tile_title">
<i class="fas fa-user tile_icon"></i> <i class="fas fa-user tile_icon"></i>
Mes Infos <span class="member_info member_name"></span>
</div> </div>
<div class="tile_content"> <div class="tile_content">
<p>Mon statut : <span class="member_info member_status"></span></p> {# <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"> <div class="delay_date_stop_container">
( jusqu'au <span class="delay_date_stop"></span> ) ( jusqu'au <span class="delay_date_stop"></span> )
</div> </div>
...@@ -29,6 +30,10 @@ ...@@ -29,6 +30,10 @@
<span>Mon numéro de coop : </span> <span>Mon numéro de coop : </span>
<span class="member_coop_number member_info"></span> <span class="member_coop_number member_info"></span>
</div> </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> </div>
<div id="see_more_info"> <div id="see_more_info">
<a href="#" id="see_more_info_link">Voir plus ></a> <a href="#" id="see_more_info_link">Voir plus ></a>
...@@ -57,6 +62,9 @@ ...@@ -57,6 +62,9 @@
Échange de services Échange de services
</div> </div>
<div class="tile_content"> <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"> <div class="home_link_button_area">
<button type="button" class="btn--primary home_link_button" id="go_to_shifts_calendar"> <button type="button" class="btn--primary home_link_button" id="go_to_shifts_calendar">
Accéder au calendrier d'échange de services Accéder au calendrier d'échange de services
...@@ -74,7 +82,6 @@ ...@@ -74,7 +82,6 @@
<a <a
href="javascript:void(0);" href="javascript:void(0);"
target="_blank" target="_blank"
type="button"
class="btn--primary home_link_button" class="btn--primary home_link_button"
id="go_to_forms" id="go_to_forms"
> >
......
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
var partner_data = { var partner_data = {
"partner_id":"{{partnerData.id}}", "partner_id":"{{partnerData.id}}",
"name":"{{partnerData.display_name}}", "name":"{{partnerData.display_name}}",
"in_ftop_team":"{{partnerData.in_ftop_team}}", "shift_type":"{{partnerData.shift_type}}",
"date_delay_stop":"{{partnerData.date_delay_stop}}", "date_delay_stop":"{{partnerData.date_delay_stop}}",
"cooperative_state":"{{partnerData.cooperative_state}}", "cooperative_state":"{{partnerData.cooperative_state}}",
"regular_shift_name":"{{partnerData.regular_shift_name}}", "regular_shift_name":"{{partnerData.regular_shift_name}}",
...@@ -99,6 +99,8 @@ ...@@ -99,6 +99,8 @@
"is_associated_people" : "{{partnerData.is_associated_people}}", "is_associated_people" : "{{partnerData.is_associated_people}}",
"parent_id" : "{{partnerData.parent_id}}", "parent_id" : "{{partnerData.parent_id}}",
"parent_name" : "{{partnerData.parent_name}}", "parent_name" : "{{partnerData.parent_name}}",
"associated_partner_id" : "{{partnerData.associated_partner_id}}",
"associated_partner_name" : "{{partnerData.associated_partner_name}}",
"verif_token" : "{{partnerData.verif_token}}", "verif_token" : "{{partnerData.verif_token}}",
} }
</script> </script>
......
...@@ -4,6 +4,10 @@ ...@@ -4,6 +4,10 @@
</div> </div>
<div class="tiles_container"> <div class="tiles_container">
<div class="tile full_width_tile" id="my_info_area"> <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="tile_content" id="my_info_content">
<div class="my_info_line"> <div class="my_info_line">
<div class="my_info_line_left"> <div class="my_info_line_left">
...@@ -58,20 +62,13 @@ ...@@ -58,20 +62,13 @@
<span class="member_address member_info"></span> <span class="member_address member_info"></span>
</div> </div>
</div> </div>
<div class="my_info_line member_mobile_line">
<div class="my_info_line_left">
Téléphone mobile
</div>
<div class="my_info_line_right member_mobile_area">
<span class="member_mobile member_info"></span>
</div>
</div>
<div class="my_info_line member_phone_line"> <div class="my_info_line member_phone_line">
<div class="my_info_line_left"> <div class="my_info_line_left">
Téléphone fixe Téléphone
</div> </div>
<div class="my_info_line_right member_phone_area"> <div class="my_info_line_right member_phone_area">
<span class="member_phone member_info"></span> <span class="member_phone member_info"></span>
<span class="member_mobile member_info"></span>
</div> </div>
</div> </div>
</div> </div>
...@@ -89,16 +86,6 @@ ...@@ -89,16 +86,6 @@
<span class="attached_partner_name member_info"></span> <span class="attached_partner_name member_info"></span>
</div> </div>
</div> </div>
<div class="my_info_line pairs_info">
<span>
Attention : Toutes les actions (changement de service, choix d'un rattrapage...)
ne sont faisables que sur l'espace membre du <b>binôme principal</b>.
</span>
<br>
<span>
Dans mon espace membre, les infos ne sont visibles qu'en lecture seule.
</span>
</div>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
</div> </div>
<div class="tile full_width_tile" id="history_area"> <div class="tile full_width_tile" id="history_area">
<div class="tile_title"> <div class="tile_title">
Historique des mouvements de points Historique de mes services
</div> </div>
<div class="loading-history"> <div class="loading-history">
<i class="fas fa-spinner fa-spin fa-lg"></i> <i class="fas fa-spinner fa-spin fa-lg"></i>
......
...@@ -13,8 +13,8 @@ ...@@ -13,8 +13,8 @@
</div> </div>
<div id="suspended_content" class="shifts_exchange_page_content"> <div id="suspended_content" class="shifts_exchange_page_content">
<h3> <h3>
J'ai <span class="makeups_nb"></span> rattrapages à effectuer, je dois les sélectionner pour pouvoir refaire mes courses. 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 les rattraper. J'ai 6 mois de délai pour le(s) rattraper.
</h3> </h3>
<h3> <h3>
Si besoin, je peux contacter le Bureau des membres via la rubrique "J'ai une demande" pour expliquer ma situation. Si besoin, je peux contacter le Bureau des membres via la rubrique "J'ai une demande" pour expliquer ma situation.
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
dataPartner = { dataPartner = {
"partner_id":"{{partnerData.id}}", "partner_id":"{{partnerData.id}}",
"name":"{{partnerData.display_name}}", "name":"{{partnerData.display_name}}",
"in_ftop_team":"{{partnerData.in_ftop_team}}", "shift_type":"{{partnerData.shift_type}}",
"final_standard_point":"{{partnerData.final_standard_point}}", "final_standard_point":"{{partnerData.final_standard_point}}",
"final_ftop_point":"{{partnerData.final_ftop_point}}", "final_ftop_point":"{{partnerData.final_ftop_point}}",
"dateProlonge":"{{partnerData.date_delay_stop}}", "dateProlonge":"{{partnerData.date_delay_stop}}",
......
...@@ -35,4 +35,19 @@ ...@@ -35,4 +35,19 @@
} }
</script> </script>
</div> </div>
<script>
// For the members space, reset url to home when accessing connect page
const is_member_space = '{{is_member_space}}';
if (is_member_space === "True") {
var app_env = '{{app_env}}';
var base_location = (app_env === 'dev') ? '/members_space/' : '/';
if (window.location.pathname === base_location) {
history.pushState({}, '', 'home');
} else {
history.replaceState({}, '', 'home');
}
}
</script>
{% endblock %} {% 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