from django.contrib import admin from outils.common_imports import * from outils.for_view_imports import * from outils.common import OdooAPI from members.models import CagetteUser from members.models import CagetteMembers from members.models import CagetteMember from shifts.models import CagetteServices from shifts.models import CagetteShift from members_space.models import CagetteMembersSpace from outils.common import MConfig from datetime import datetime, date default_msettings = {'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é-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 la durée de l\'extension', 'type': 'text', 'value': '', 'class': 'link', 'sort_order': 21 }, 'on_picking_shift_template_msg': { 'title': 'Afficher une info à la sélection d\'un créneau (jour,heure) en respectant la syntaxe en exemple : lundi 14:00 Ici votre message', 'type': 'text', 'value': '', 'sort_order': 22 }, } def config(request): """Page de configuration.""" template = loader.get_template('outils/config.html') context = {'title': 'Configuration module Membres', 'module': 'Membres'} return HttpResponse(template.render(context, request)) def get_settings(request): result = {} is_connected_user = CagetteUser.are_credentials_ok(request) if is_connected_user is True: try: msettings = MConfig.get_settings('members') if len(msettings) == 0: msettings = default_msettings # take care that every params will be shown (consider newly added params) for k, v in default_msettings.items(): if not (k in msettings): msettings[k] = v for k,v in msettings.items(): if 'sort_order' not in v: msettings[k]['sort_order'] = 1 result['settings'] = dict(sorted(msettings.items(), key=lambda k_v: k_v[1]['sort_order'])) # on preprod server, dict order (through JsonResponse ??) is not respected !! except Exception as e: result['error'] = str(e) else: result['error'] = "Forbidden" return JsonResponse({"res": result}, safe=False) def save_settings(request): result = {} is_connected_user = CagetteUser.are_credentials_ok(request) if is_connected_user is True: try: params = json.loads(request.POST.get('params')) result['save'] = MConfig.save_settings('members', params) except Exception as e: result['error'] = str(e) else: result['error'] = "Forbidden" return JsonResponse({"res": result}, safe=False) def module_settings(request): if request.method == 'GET': return get_settings(request) else: return save_settings(request) def add_pts_to_everybody(request, pts, reason): result = {} is_connected_user = CagetteUser.are_credentials_ok(request) if is_connected_user is True: try: fields = ['shift_type'] cond = [['is_member', '=', True]] all_members = CagetteMembers.get(cond, fields) if all_members and len(all_members) > 0: ftop_ids = [] standard_ids = [] for m in all_members: if m['shift_type'] == 'ftop': ftop_ids.append(m['id']) else: standard_ids.append(m['id']) if len(standard_ids) > 0: result['standard'] = CagetteMembers.add_pts_to_everyone('standard', standard_ids, pts, reason) else: result['standard'] = 'No standard found ! ' if len(ftop_ids) > 0: result['ftop'] = CagetteMembers.add_pts_to_everyone('ftop', ftop_ids, pts, reason) else: result['ftop'] = 'No FTOP found !' # result['ftop'] = ftop_ids # result['standard'] = standard_ids except Exception as e: result['error'] = str(e) else: result['error'] = "Forbidden" return JsonResponse({'res': result}) def manage_mess(request): """Admin part to manage mess - uncomplete subscription""" is_connected_user = CagetteUser.are_credentials_ok(request) template = loader.get_template('members/manage_mess.html') context = {'title': 'Gestion des inscriptions problématiques', 'couchdb_server': settings.COUCHDB['url'], 'db': settings.COUCHDB['dbs']['member_mess'], 'is_connected_user': is_connected_user} return HttpResponse(template.render(context, request)) # JsonResponse({'error' : str(e)}, status=500) def raw_search(request): res = {} is_connected_user = CagetteUser.are_credentials_ok(request) if is_connected_user is True: try: needle = str(request.GET.get('needle')) members = CagetteMembers.raw_search(needle) res = {'members': members} except Exception as e: res['error'] = str(e) response = JsonResponse(res) else: response = JsonResponse(res, status=403) return response def problematic_members(request): res = {} is_connected_user = CagetteUser.are_credentials_ok(request) if is_connected_user is True: try: members = CagetteMembers.get_problematic_members() res = {'members': members} except Exception as e: res['error'] = str(e) response = JsonResponse(res) else: response = JsonResponse(res, status=403) return response def remove_member_from_mess_list(request): res = {} is_connected_user = CagetteUser.are_credentials_ok(request) if is_connected_user is True: try: res = CagetteMember.remove_from_mess_list(request) except Exception as e: res['error'] = str(e) response = JsonResponse(res) else: response = JsonResponse(res, status=403) return response def generate_barcode(request, member_id): res = {} is_connected_user = CagetteUser.are_credentials_ok(request) if is_connected_user is True: try: res['done'] = CagetteMember(member_id).generate_barcode() except Exception as e: res['error'] = str(e) response = JsonResponse(res, safe=False) else: response = JsonResponse(res, status=403) return response def generate_base_and_barcode(request, member_id): res = {} is_connected_user = CagetteUser.are_credentials_ok(request) if is_connected_user is True: try: res['done'] = CagetteMember(member_id).generate_base_and_barcode() except Exception as e: res['error'] = str(e) response = JsonResponse(res, safe=False) else: response = JsonResponse(res, status=403) return response def create_envelops(request): """Only used from manage_mess, which was a tempory fonctionality""" res = {} is_connected_user = CagetteUser.are_credentials_ok(request) if is_connected_user is True: try: res['result'] = CagetteMember.standalone_create_envelops(request) except Exception as e: res['error'] = str(e) response = JsonResponse(res, safe=False) else: response = JsonResponse(res, status=403) return response # # # ADMIN / BDM # # # def admin(request): """ Administration des membres """ template = loader.get_template('members/admin/index.html') context = {'title': 'BDM', 'module': 'Membres', 'admin_binome_active': getattr(settings, 'ADMIN_BINOME_ACTIVE', True),} return HttpResponse(template.render(context, request)) def manage_makeups(request): """ Administration des membres """ template = loader.get_template('members/admin/manage_makeups.html') committees_shift_id = CagetteServices.get_committees_shift_id() m = CagetteMembersSpace() context = {'title': 'BDM - Rattrapages', 'module': 'Membres', 'has_committe_shift': committees_shift_id is not None, 'extension_duration': m.get_extension_duration() } return HttpResponse(template.render(context, request)) def manage_shift_registrations(request): """ Administration des services des membres """ template = loader.get_template('members/admin/manage_shift_registrations.html') context = {'title': 'BDM - Services', 'module': 'Membres'} return HttpResponse(template.render(context, request)) def manage_attached(request): """ Administration des binômes membres """ template = loader.get_template('members/admin/manage_attached.html') context = {'title': 'BDM - Binômes', 'module': 'Membres'} return HttpResponse(template.render(context, request)) def manage_regular_shifts(request): """ Administration des créneaux des membres """ template = loader.get_template('members/admin/manage_regular_shifts.html') committees_shift_id = CagetteServices.get_committees_shift_id() committees_shift_name = getattr(settings, 'COMMITTEES_SHIFT_NAME', "service des Comités") exemptions_shift_id = CagetteServices.get_exemptions_shift_id() context = { 'title': 'BDM - Créneaux', 'module': 'Membres', 'couchdb_server': settings.COUCHDB['url'], 'db': settings.COUCHDB['dbs']['member'], 'max_begin_hour': settings.MAX_BEGIN_HOUR, 'mag_place_string': settings.MAG_NAME, 'open_on_sunday': getattr(settings, 'OPEN_ON_SUNDAY', False), 'show_ftop_button': getattr(settings, 'BDM_SHOW_FTOP_BUTTON', True), 'has_committe_shift': committees_shift_id is not None, 'committees_shift_id': committees_shift_id, 'committees_shift_name': committees_shift_name, 'ASSOCIATE_MEMBER_SHIFT' : getattr(settings, 'ASSOCIATE_MEMBER_SHIFT', ''), 'exemptions_shift_id': exemptions_shift_id, } return HttpResponse(template.render(context, request)) def get_makeups_members(request): """ Récupération des membres qui doivent faire des rattrapages """ res = CagetteMembers.get_makeups_members() return JsonResponse({ 'res' : res }) def get_attached_members(request): """ Récupération des membres en binôme """ res = CagetteMembers.get_attached_members() return JsonResponse({ 'res' : res }) def update_members_makeups(request): """ Met à jour les rattrapages des membres passés dans la requête """ res = {} is_connected_user = CagetteUser.are_credentials_ok(request) if is_connected_user is True: members_data = json.loads(request.body.decode()) res["res"] = [] update_members_makeups_core(members_data, res) response = JsonResponse(res) else: res["message"] = "Unauthorized" response = JsonResponse(res, status=403) return response def update_members_makeups_core(members_data, res): for member_data in members_data: cm = CagetteMember(int(member_data["member_id"])) res["res"].append(cm.update_member_makeups(member_data)) # Update member standard points, for standard members only if member_data["member_shift_type"] == "standard": # Set points to minus the number of makeups to do + the makeups to come (limited to -2) cs = CagetteShift() shift_data = cs.get_shift_partner(int(member_data["member_id"])) target_points = - int(member_data["target_makeups_nb"]) - sum(1 for value in shift_data if value['is_makeup']) if (target_points < -2): target_points = -2 member_points = cm.get_member_points("standard") points_diff = abs(member_points - target_points) # Don't update if no change if points_diff == 0: res["res"][-1]['standard_points'] = member_points continue if member_points > target_points: points_update = - points_diff else: points_update = points_diff data = { 'name': "Admin BDM - " + member_data["description"], 'shift_id': False, 'type': member_data["member_shift_type"], 'partner_id': int(member_data["member_id"]), 'point_qty': points_update } cm.update_member_points(data) #There are some odoo process happening here that could change the actual number of points #so we want to fetch it again to send it back res["res"][-1]['standard_points'] = cm.get_member_points("standard") # Better to call run_process_target_status now, otherwise partner remains # in alert until routine is called (every 5 minutes). It is a bit weird for users and # allocation of rattrapages before the routine is executed will not trigger change to delay state ! # (the parner would have to go back to espace membre and click on "j'affecte mes rattrapage" # even though it shows 'J'ai 0 rattrapages à effecter' for the delay state change to be eventually triggered) api = OdooAPI() api.execute('res.partner', 'run_process_target_status', []) def regenerate_member_delay(request): """ From BDM admin, close existing extension if exists & recreate for 6 months """ res = {} is_connected_user = CagetteUser.are_credentials_ok(request) if is_connected_user is True: raw_data = json.loads(request.body.decode()) # Close extension if has one member_id = int(raw_data["member_id"]) cm = CagetteMember(member_id) cm.close_extension() # Recreate starting now cs = CagetteShift() data = { "idPartner": member_id, "start_date": date.today().isoformat() } duration = raw_data["duration"] ext_name = "Délai étendue depuis l'admin BDM" res["create_delay"] = cs.create_delay(data=data, duration=duration, ext_name=ext_name) if (res["create_delay"]): try: # Add 0 pt to counter so odoo updates member status data = { 'name': "Forcer l'entrée en délai", 'shift_id': False, 'type': "standard", 'partner_id': member_id, 'point_qty': 0 } cm.update_member_points(data) data = { 'name': "Forcer l'entrée en délai", 'shift_id': False, 'type': "ftop", 'partner_id': member_id, 'point_qty': 0 } cm.update_member_points(data) res["force_entry_delay"] = True except Exception as e: print(str(e)) else: coop_logger.error("regenerate_member_delay: %s, %s", str(res["create_delay"]), str(data)) return HttpResponseServerError() res["member_data"] = CagetteMembers.get_makeups_members([member_id])[0] response = JsonResponse(res, safe=False) else: res["message"] = "Unauthorized" response = JsonResponse(res, status=403) return response # --- Gestion des créneaux def delete_shift_registration(request): """ From BDM admin, delete (cancel) a member shift registration """ res = {} is_connected_user = CagetteUser.are_credentials_ok(request) if is_connected_user is True: data = json.loads(request.body.decode()) member_id = int(data["member_id"]) shift_registration_id = int(data["shift_registration_id"]) shift_is_makeup = data["shift_is_makeup"] cancellation_description = data["cancellation_description"] # Note: 'upcoming_registration_count' in res.partner won't change because the _compute method # in odoo counts canceled shift registrations. m = CagetteShift() res["cancel_shift"] = m.cancel_shift([shift_registration_id], origin='bdm', description=cancellation_description) if shift_is_makeup is True: fields = { 'name': "Admin BDM (annulation de rattrapage par une annulation de présence) - " + cancellation_description, 'shift_id': False, 'type': data["member_shift_type"], 'partner_id': member_id, 'point_qty': 1 } res["update_counter"] = m.update_counter_event(fields) response = JsonResponse(res, safe=False) else: res["message"] = "Unauthorized" response = JsonResponse(res, status=403) return response def delete_shift_template_registration(request): """ From BDM admin, delete a member shift template registration """ res = {} is_connected_user = CagetteUser.are_credentials_ok(request) if is_connected_user is True: try: data = json.loads(request.body.decode()) partner_id = int(data["partner_id"]) shift_template_id = int(data["shift_template_id"]) makeups_to_do = int(data["makeups_to_do"]) permanent_unsuscribe = data["permanent_unsuscribe"] cm = CagetteMember(partner_id) # Get partner nb of future makeup shifts partner_makeups = cm.get_member_selected_makeups() target_makeup = makeups_to_do + len(partner_makeups) if target_makeup > 2: target_makeup = 2 # Update partner makeups to do res["update_makeups"] = cm.update_member_makeups({'target_makeups_nb': target_makeup}) # Delete all shift registrations & shift template registration res["unsubscribe_member"] = cm.unsubscribe_member() if permanent_unsuscribe is True: res["set_done"] = cm.set_cooperative_state("gone") if res["set_done"]: """ Delete pair(s?) of partner if it is a parent to improve statistics (#4810) """ api = OdooAPI() associated_members = api.search_read('res.partner', [['parent_id', '=', partner_id]], ['id']) for am in associated_members: data = {"child": {"id": am["id"]}, "gone": ["parent", "child"]} delete_pair_core(data) except Exception as e: res["error"] = str(e) response = JsonResponse(res, safe=False) else: res["message"] = "Unauthorized" response = JsonResponse(res, status=403) return response def shift_subscription(request): """ Register a member to a shift template. If the member was already subscribed to a shift template, unsubscribe him.her first and delete all existing shifts EXCEPT makeups. """ res = {} data = json.loads(request.body.decode()) partner_id = int(data["partner_id"]) is_allowed = CagetteUser.are_credentials_ok(request) if is_allowed is False: credentials = CagetteMember.get_credentials(request, with_id = True) if 'success' in credentials and credentials['success'] is True and credentials['id'] == partner_id: is_allowed = True if is_allowed is True: api = OdooAPI() partner_id = int(data["partner_id"]) shift_type = data["shift_type"] moving_from_std_to_ftop = False if shift_type == 1: # 1 = standard shift_template_id = int(data["shift_template_id"]) elif shift_type == 2: # 2 = ftop # First try to get committees shift shift_template_id = CagetteServices.get_committees_shift_id() # If None, no committees shift, get the first ftop shift if shift_template_id is None: shift_template_id = CagetteServices.get_first_ftop_shift_id() c = [['id', '=', partner_id]] f = ['shift_type'] moving_from_std_to_ftop = api.search_read('res.partner', c, f)[0]['shift_type'] == 'standard' else: # 3 = exempté # Get exemptions shift shift_template_id = CagetteServices.get_exemptions_shift_id() m = CagetteMember(partner_id) unsubscribe_first = data["unsubscribe_first"] if unsubscribe_first is True: # If the member is registered to a shift on the shift template, registering to this shift template will fail. has_makeups_in_new_shift = m.is_member_registered_to_makeup_shift_template(shift_template_id) if has_makeups_in_new_shift is True: return JsonResponse( { "message": "A makeup is registered on this shift template", "code": "makeup_found" }, status=409 ) changing_shift = not moving_from_std_to_ftop res["unsubscribe_member"] = m.unsubscribe_member(changing_shift) if moving_from_std_to_ftop: lower_makeup_count_to_zero_if_moving_from_std_to_ftop(partner_id, res) reg_id = m.create_coop_shift_subscription(shift_template_id, shift_type) # Return necessary data if reg_id is not None: c = [['id', '=', shift_template_id]] f = ['id', 'name'] res["shift_template"] = api.search_read('shift.template', c, f)[0] c = [['id', '=', partner_id]] f = ['cooperative_state'] res["cooperative_state"] = api.search_read('res.partner', c, f)[0]['cooperative_state'] coop_logger.info("Resultat shift_subscription : %s (données reçues = %s)", str(res), str(data)) response = JsonResponse(res) else: response = JsonResponse({"message": "Subscription failed"}, status=500) else: response = JsonResponse({"message": "Unauthorized"}, status=403) return response def lower_makeup_count_to_zero_if_moving_from_std_to_ftop(partner_id, res): members_data = [] members_data.append({ 'member_id': partner_id, 'member_shift_type': 'standard', 'target_makeups_nb': 0, 'description': 'reset automatique du compteur rattrapages suite changement créneau standard vers non standard' }) res["res"] = [] update_members_makeups_core(members_data, res) if res["res"][0]["update"]: res["makeups_to_do"] = 0 # --- Gestion des binômes def get_member_info(request, id): """Retrieve information about a member.""" res = {} is_connected_user = CagetteUser.are_credentials_ok(request) if is_connected_user: api = OdooAPI() fields = [ 'id', 'name', 'sex', 'cooperative_state', 'email', 'street', 'street2', 'zip', 'city', 'current_template_name', 'shift_type', 'parent_id', 'is_associated_people', 'parent_name', "makeups_to_do", "barcode_base" ] cond = [['id', '=', id]] member = api.search_read('res.partner', cond, fields) if member: member = member[0] parent = None if member['parent_id']: res_parent = api.search_read('res.partner', [['id', '=', int(member['parent_id'][0])]], ['barcode_base', 'email']) if res_parent: parent = res_parent[0] member['parent_barcode_base'] = parent['barcode_base'] member['parent_email'] = parent['email'] res['member'] = member response = JsonResponse(res) else: response = JsonResponse({"message": "Not found"}, status=404) else: res['message'] = "Unauthorized" response = JsonResponse(res, status=403) return response def create_pair(request): """Create pair payload example: { "parent": {"id": 3075}, "child": {"id": 3067} } """ if request.method == 'GET': template = loader.get_template('members/admin/manage_attached_create_pair.html') context = {'title': 'BDM - Binômes', 'module': 'Membres'} return HttpResponse(template.render(context, request)) if request.method == 'POST': if CagetteUser.are_credentials_ok(request): api = OdooAPI() data = json.loads(request.body.decode()) parent_id = data['parent']['id'] child_id = data['child']['id'] # create attached account for child fields = [ "birthdate", "city", "commercial_partner_id", "company_id", "company_type", "cooperative_state", "barcode_rule_id", "country_id", "customer", "department_id", "email", "employee", "image", "image_medium", "image_small", "mobile", "name", "phone", "sex", "street", "street2", "zip", "nb_associated_people", "current_template_name", "parent_id", "is_associated_people", "makeups_to_do", "final_standard_points", "final_ftop_points", "shift_type" ] child = api.search_read('res.partner', [['id', '=', child_id]], fields)[0] parent = api.search_read('res.partner', [['id', '=', parent_id]], ['commercial_partner_id', 'nb_associated_people', 'current_template_name', 'makeups_to_do', "final_standard_points", "final_ftop_points", 'shift_type' 'parent_id'])[0] errors = [] if child['nb_associated_people'] > 0: # le membre est déjà titulaire d'un binôme errors.append("Le membre suppléant sélectionné est titulaire d'un bînome") # le membre suppléant fait parti du commité? if child['current_template_name'] == "Services des comités": errors.append("Le membre suppléant séléctionné fait parti du comité") # Verifier que le suppléant n'est pas déjà en binôme soit titulaire soit suppléant for m in api.search_read('res.partner', [['email', '=', child['email']]]): if m['is_associated_people']: errors.append('Le membre suppléant est déjà en bînome') if m['child_ids']: errors.append("Le membre suppléant sélectionné est titulaire d'un binôme") # le membre titulaire a déjà un/des suppléants? if parent['nb_associated_people'] >= 1: # On récupère le/s suppléant(s) associated_members = api.search_read('res.partner', [['parent_id', '=', parent_id]], ['id', 'age']) # le suppléant est un mineur? for m in associated_members: if m['age'] > 18: errors.append("Le membre titulaire sélectionné a déjà un suppléant") if errors: return JsonResponse({"errors": errors}, status=409) del child["id"] for field in child.keys(): if field.endswith("_id"): try: child[field] = child[field][0] except TypeError: child[field] = False child['is_associated_people'] = True child['parent_id'] = parent['id'] # Following lines are useful if parent or child is unsubscribed if not 'shift_type' in parent: parent['shift_type'] = 'standard' if not 'shift_type' in child: child['shift_type'] = 'standard' # fusion des rattrapages child_makeups = child['makeups_to_do'] parent_makeups = parent['makeups_to_do'] child_scheduled_makeups = api.search_read('shift.registration', [['partner_id', '=', child_id], ['is_makeup', '=', True], ['state', '=', 'open'], ['date_begin', '>', datetime.now().isoformat()]]) parent_scheduled_makeups = api.search_read('shift.registration', [['partner_id', '=', parent_id], ['is_makeup', '=', True], ['state', '=', 'open'], ['date_begin', '>', datetime.now().isoformat()]]) child_makeups += len(child_scheduled_makeups) parent_makeups += len(parent_scheduled_makeups) if child_makeups: # le suppléant a des rattrapages if child_makeups + parent_makeups <=2: # on transfert les rattrapages sur le parent # Comme on annule les services du suppléant, on ajoute en makeup_to_do du titulaire les rattrapages choisis ou non du suppléant # On annule les rattrapages du child api.update('res.partner', [child_id], {"makeups_to_do": 0}) for makeup in range(child_makeups): # reset du compteur du suppléant api.create('shift.counter.event', {"name": 'passage en binôme', "shift_id": False, "type": child['shift_type'], "partner_id": child_id, "point_qty": 1}) # on retire les points au titulaire, les rattrages sont automatiquement ajoutés api.create('shift.counter.event', {"name": 'passage en binôme', "shift_id": False, "type": parent['shift_type'], "partner_id": parent_id, "point_qty": -1}) elif child_makeups + parent_makeups > 2: # on annule les rattrapages du suppléant et on met 2 rattrapages sur le titulaire api.update('res.partner', [child_id], {"makeups_to_do": 0}) for makeup in range(child_makeups): # reset du compteur du suppléant api.create('shift.counter.event', {"name": 'passage en binôme', "shift_id": False, "type": child['shift_type'], "partner_id": child_id, "point_qty": 1}) for i in range(abs(parent_makeups - 2)): # màj du compteur du titulaire api.create('shift.counter.event', {"name": "passage en binôme", "shift_id": False, "type": parent['shift_type'], "partner_id": parent_id, "point_qty": -1}) # No more useful since status is fully managed by lacagette_addons modules #try: # api.execute('res.partner', 'run_process_target_status', []) #except: # pass m = CagetteMember(child_id).unsubscribe_member() # update child base account state api.update("res.partner", [child_id], {'cooperative_state': "associated"}) # get barcode rule id bbcode_rule = api.search_read("barcode.rule", [['for_associated_people', "=", True]], ['id'])[0] child['barcode_rule_id'] = bbcode_rule["id"] child['cooperative_state'] = 'associated' for field in ["nb_associated_people", "current_template_name", "makeups_to_do", "final_standard_points", "final_ftop_points", "shift_type"]: try: del child[field] except KeyError: pass attached_account = api.create('res.partner', child) # generate_base api.execute('res.partner', 'generate_base', [attached_account]) response = JsonResponse({"message": "Succesfuly paired members"}, status=200) else: response = JsonResponse({"message": "Unauthorized"}, status=403) return response else: return JsonResponse({"message": "Method Not Allowed"}, status=405) def delete_pair(request): """ Administration des binômes membres Delete pair GET: Return template POST: payload example: { "child": { "id": "1620" }, "gone": [ "parent", "child" ] } """ if request.method == 'GET': template = loader.get_template('members/admin/manage_attached_delete_pair.html') context = {'title': 'BDM - Binômes', 'module': 'Membres'} return HttpResponse(template.render(context, request)) elif request.method == 'POST': if CagetteUser.are_credentials_ok(request): data = json.loads(request.body.decode()) delete_pair_core(data) response = JsonResponse({"message": "Succesfuly unpaired members"}, status=200) else: response = JsonResponse({"message": "Unauthorized"}, status=403) return response else: return JsonResponse({"message": "Method Not Allowed"}, status=405) def delete_pair_core(data): """ Core of delete_pair argument example : { "child": { "id": "1620" }, "gone": [ "parent", "child" ] } """ api = OdooAPI() child_id = int(data['child']['id']) child = api.search_read('res.partner', [['id', '=', child_id]], ['email', 'id', 'parent_id'])[0] child_accounts = api.search_read('res.partner', [['email', '=', child['email']]], ['id', 'email']) prev_child = [x['id'] for x in child_accounts if x['id'] != child_id] parent = api.search_read('res.partner', [['id', '=', child['parent_id'][0]]], ['cooperative_state'])[0] api.update('res.partner', [child_id], {"parent_id": False, "is_associated_people": False, "active": False, "is_former_associated_people": True}) child_update_fields = {'cooperative_state': "unsubscribed", "is_former_associated_people": True} if 'gone' in data and 'child' in data['gone']: child_update_fields['cooperative_state'] = "gone" for id in prev_child: api.update("res.partner", [id], child_update_fields) if 'gone' in data and 'parent' in data['gone']: api.update("res.partner", [parent['id']], {'cooperative_state': "gone", "is_former_associated_people": True})