from django.shortcuts import render, redirect , get_object_or_404
from django.contrib.auth import authenticate, login, logout
from django.contrib import messages
from .forms import *
from .models import *
from django.db import connection
from django.views.decorators.cache import never_cache
from django.core import serializers
from django.http import JsonResponse
from django.template.loader import render_to_string
from django.forms.models import model_to_dict
from django_user_agents.utils import get_user_agent
from django.conf import settings
from django.db.models import Q
from django.db.models import F
from datetime import datetime
from datetime import timedelta
from django.core.mail import EmailMessage
from django.http import HttpResponse
from django.contrib.auth.models import User
from urllib.parse import parse_qs
from django.http import FileResponse
# apparently openpyxl import * is not working to replace from openpyxl import Workbook
#import openpyxl.workbook.workbook
from openpyxl import Workbook, load_workbook #to add to requirement.txt
from openpyxl.styles import * #to add to requirement.txt
from openpyxl.drawing.image import Image
from openpyxl.drawing.spreadsheet_drawing import AnchorMarker, TwoCellAnchor
import re
import subprocess
import os
import operator
from functools import reduce
import copy
from urllib.parse import parse_qs
import json
#from openpyxl.styles import Font, Alignment, PatternFill


####################################################################################
def export_to_excel_or_pdf(request, xlsx_or_pdf, current_sales_documents_id):
    try:


        if xlsx_or_pdf not in ['xlsx', 'pdf', 'pdf_mail']:
            return JsonResponse({'error': 'Invalid export format'}, status=400)

        sales_documents_queryset = models_sales_documents.objects.filter(id_sales_documents=current_sales_documents_id)
        if not sales_documents_queryset.exists():
            return JsonResponse({'error': 'Document not found'}, status=404)

        doc = sales_documents_queryset[0]

        billing_address_id = getattr(doc, 'sales_documents_billing_address_id', '')
        billing_address = models_addresses.objects.filter(id_address=billing_address_id).first()
        line1 = f"{billing_address.address_number or ''} {billing_address.address_street_name_1 or ''}".strip() if billing_address else ""
        line2 = f"{billing_address.address_postal_code or ''} - {billing_address.address_city or ''}".strip() if billing_address else ""

        contact_id = getattr(doc, 'sales_documents_ref_contact_id', '')

        document_type = request.GET.get('document_type', '')
        if document_type == 'quote':
            document_type = 'Devis'
        if document_type == 'delivery_note':
            document_type = 'Bon de livraison'
        if document_type == 'invoice':
            document_type = 'Facture'
        document_number = request.GET.get('document_number', '')
        company_id = request.GET.get('company_num', '')
        contact = models_contacts.objects.filter(id_contact=contact_id).first()
        company = models_companies.objects.filter(id_company=company_id).first()
        contact_str_1 = f"{contact.contact_gender or ''} {contact.contact_last_name or ''} {contact.contact_first_name or ''}".strip() if contact else ""
        contact_str_2 = f"{contact.contact_phone_1 or ''} {contact.contact_email_1 or ''}".strip() if contact else ""
        company_str = f"{company.company_name or ''}".strip() if company else ""

        total_cat1 = request.GET.get('total_category_1', '')
        total_cat2 = request.GET.get('total_category_2', '')
        total_cat3 = request.GET.get('total_category_3', '')

        product_id_to_name = {
            str(p.id_product): p.product_denomination
            for p in models_products.objects.all()
        }

        doc_dict = model_to_dict(doc)
        suffixes = sorted({k.split("_")[-1] for k in doc_dict if k.split("_")[-1].isdigit()})
        list_of_line_dicts = [
            {k: v for k, v in doc_dict.items() if k.endswith(f"_{suffix}")}
            for suffix in suffixes
        ]
        index_line_map = []
        for line_dict in list_of_line_dicts:
            for k, v in line_dict.items():
                if "sales_documents_index_line_" in k:
                    index_line_map.append({str(v): k.split("_")[-1]})

        workbook = load_workbook(os.path.join(settings.BASE_DIR, "Tonal_Devis_Template.xlsx"))
        worksheet = workbook["Sheet_1"]

        worksheet.page_margins.left = 0.12
        worksheet.page_margins.right = 0.12
        worksheet.page_margins.top = 0.12
        worksheet.page_margins.bottom = 0.12
        worksheet.column_dimensions['A'].hidden = True
        worksheet.page_setup.horizontalCentered = True

        worksheet.cell(row=2, column=5, value=document_type).alignment = Alignment(horizontal='left', vertical='center')
        worksheet.cell(row=2, column=9, value=document_number).alignment = Alignment(horizontal='right', vertical='center')
        worksheet.merge_cells(start_row=5, start_column=6, end_row=5, end_column=9)
        worksheet.cell(row=5, column=6, value=company_str).alignment = Alignment(horizontal='left', vertical='center')
        worksheet.merge_cells(start_row=6, start_column=6, end_row=6, end_column=9)
        worksheet.cell(row=6, column=6, value=line1).alignment = Alignment(horizontal='left', vertical='center')
        worksheet.merge_cells(start_row=7, start_column=6, end_row=7, end_column=9)
        worksheet.cell(row=7, column=6, value=line2).alignment = Alignment(horizontal='left', vertical='center')
        worksheet.merge_cells(start_row=8, start_column=6, end_row=8, end_column=9)
        worksheet.cell(row=8, column=6, value=contact_str_1).alignment = Alignment(horizontal='left', vertical='center')
        worksheet.merge_cells(start_row=9, start_column=6, end_row=9, end_column=9)
        worksheet.cell(row=9, column=6, value=contact_str_2).alignment = Alignment(horizontal='left', vertical='center')

        img = Image(os.path.join(settings.BASE_DIR, "Tonal_logo.png"))
        img.anchor = TwoCellAnchor(
            editAs="twoCell",
            _from=AnchorMarker(col=1, row=0, colOff=30000, rowOff=30000),
            to=AnchorMarker(col=4, row=4, colOff=-30000, rowOff=-30000)
        )
        worksheet.add_image(img)

        category_total_map = {
            'materiel': {'total': total_cat1, 'fill': PatternFill(start_color="fae9db", end_color="fae9db", fill_type="solid")},
            'etude, conception, realisation': {'total': total_cat3, 'fill': PatternFill(start_color="ebf0df", end_color="ebf0df", fill_type="solid")},
            'transport': {'total': total_cat2, 'fill': PatternFill(start_color="dce5f0", end_color="dce5f0", fill_type="solid")},
        }

        row = 16
        for index in range(len(list_of_line_dicts)):
            row += 1
            line_content, desc, suffix = [], "", ""

            for idx_dict in index_line_map:
                if str(index + 1) in idx_dict:
                    suffix = idx_dict[str(index + 1)]
                    product_id = getattr(doc, f"sales_documents_description_{suffix}", "")
                    desc = product_id_to_name.get(str(product_id), "").strip()
                    desc_key = desc.lower()

                    desc_free = getattr(doc, f"sales_documents_description_free_{suffix}", "")
                    price = getattr(doc, f"sales_documents_price_{suffix}", "")
                    discount = getattr(doc, f"sales_documents_discount_{suffix}", "")
                    quantity = getattr(doc, f"sales_documents_quantity_{suffix}", "")
                    calculated_price = getattr(doc, f"sales_documents_calculated_price_{suffix}", "")
                    discounted_price = getattr(doc, f"sales_documents_discounted_price_{suffix}", "")
                    line_content = [desc, desc_free, price, quantity, calculated_price, discount, discounted_price]

            category_info = category_total_map.get(desc_key, None)
            is_last_of_category = True
            for future_index in range(index + 1, len(list_of_line_dicts)):
                for idx_dict in index_line_map:
                    if str(future_index + 1) in idx_dict:
                        future_suffix = idx_dict[str(future_index + 1)]
                        future_product_id = getattr(doc, f"sales_documents_description_{future_suffix}", "")
                        future_desc = product_id_to_name.get(str(future_product_id), "").strip().lower()
                        if future_desc == desc_key:
                            is_last_of_category = False
                            break
                if not is_last_of_category:
                    break

            if category_info and is_last_of_category:
                line_content[-1] = category_info['total']
            else:
                line_content[-1] = discounted_price

            fill = category_info['fill'] if category_info else None

            if desc_key == 'materiel':
                worksheet.cell(row=row, column=2, value=desc.upper()).alignment = Alignment(horizontal='left', vertical='center')
                worksheet.cell(row=row, column=2).font = Font(name='Arial', size=10, bold=True)
                if fill: worksheet.cell(row=row, column=2).fill = fill

                worksheet.cell(row=row, column=3, value="").alignment = Alignment(vertical='center')
                if fill: worksheet.cell(row=row, column=3).fill = fill

                worksheet.cell(row=row, column=4, value=desc_free).alignment = Alignment(horizontal='right', vertical='center')
                worksheet.cell(row=row, column=4).font = Font(name='Arial', size=10)
                if fill: worksheet.cell(row=row, column=4).fill = fill

                for col_index, value in zip(range(5, 10), line_content[2:]):
                    cell = worksheet.cell(row=row, column=col_index, value=value)
                    if col_index == 5:
                        cell.alignment = Alignment(horizontal='left', vertical='center')
                        cell.font = Font(name='Arial', size=10, bold=True)
                    elif col_index == 6:
                        cell.alignment = Alignment(horizontal='right', vertical='center')
                        cell.font = Font(name='Arial', size=10, bold=True)
                    elif col_index == 7:
                        cell.alignment = Alignment(horizontal='left', vertical='center')
                    elif col_index == 8:
                        cell.alignment = Alignment(horizontal='center', vertical='center')
                    elif col_index == 9:
                        cell.alignment = Alignment(horizontal='right', vertical='center')
                    if fill:
                        cell.fill = fill
                    if fill and col_index == 9 and is_last_of_category:
                        cell.font = Font(name='Arial', size=10, bold=True)
            else:
                for col in range(2, 5):
                    cell = worksheet.cell(row=row, column=col)
                    cell.alignment = Alignment(vertical='center')
                    if fill:
                        cell.fill = fill

                worksheet.cell(row=row, column=2, value=f"{desc} {desc_free}").alignment = Alignment(horizontal='left', vertical='center')
                worksheet.cell(row=row, column=2).font = Font(name='Arial', size=10, bold=True if fill else False)
                worksheet.merge_cells(start_row=row, start_column=2, end_row=row, end_column=4)

                for col_index, value in zip(range(5, 10), line_content[2:]):
                    cell = worksheet.cell(row=row, column=col_index, value=value)
                    if col_index in [5, 6, 7, 8]:
                        cell.alignment = Alignment(horizontal='center', vertical='center')
                    elif col_index == 9:
                        cell.alignment = Alignment(horizontal='right', vertical='center')
                    if fill:
                        cell.fill = fill
                    if fill and col_index == 9 and is_last_of_category:
                        cell.font = Font(name='Arial', size=10, bold=True)

        worksheet.print_area = f"A1:I{max(row + 1, 54)}"

        excel_path = os.path.join(settings.BASE_DIR, f"Tonal_Devis_{current_sales_documents_id}.xlsx")
        workbook.save(excel_path)

        if xlsx_or_pdf == 'xlsx':
            with open(excel_path, 'rb') as f:
                file_data = f.read()
            os.remove(excel_path)
            response = HttpResponse(
                file_data,
                content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
            )
            response['Content-Disposition'] = f'attachment; filename=Tonal_Devis_{current_sales_documents_id}.xlsx'
            return response

        subprocess.run([
            'libreoffice', '--headless', '--convert-to', 'pdf', '--outdir', settings.BASE_DIR, excel_path
        ], check=True)

        pdf_path = os.path.join(settings.BASE_DIR, f"Tonal_Devis_{current_sales_documents_id}.pdf")
        if not os.path.exists(pdf_path):
            return JsonResponse({'error': 'PDF conversion failed'}, status=500)

        with open(pdf_path, 'rb') as f:
            pdf_data = f.read()

        # Supprime les fichiers temporaires
        os.remove(pdf_path)
        if os.path.exists(excel_path):
            os.remove(excel_path)

        if xlsx_or_pdf == 'pdf_mail':
            email_to = [e.strip() for e in request.POST.get('to', '').replace(';', ',').split(',') if e.strip()]
            email_cc = [e.strip() for e in request.POST.get('cc', '').replace(';', ',').split(',') if e.strip()]
            email_bcc = [e.strip() for e in request.POST.get('bcc', '').replace(';', ',').split(',') if e.strip()]

            subject = request.POST.get('subject', 'Votre devis PDF')
            body_html = request.POST.get('content', '')

            if not email_to:
                return JsonResponse({'error': 'Adresse e-mail du destinataire manquante'}, status=400)

            try:
                email = EmailMessage(
                    subject=subject,
                    body=body_html,
                    from_email=settings.DEFAULT_FROM_EMAIL,
                    to=email_to,
                    cc=email_cc,
                    bcc=email_bcc,
                )

                email.content_subtype = 'html'
                email.attach(f"Tonal_Devis_{current_sales_documents_id}.pdf", pdf_data, 'application/pdf')

                # ✅ Ajout de la pièce jointe personnalisée (si présente)
                for custom_file in request.FILES.getlist('custom_attachment'):
                    email.attach(custom_file.name, custom_file.read(), custom_file.content_type)

                email.send()

                return JsonResponse({'message': f'PDF envoyé à {email_to}'})
            except Exception as e:
                return JsonResponse({'error': f'Échec de l\'envoi du mail : {str(e)}'}, status=500)

        # Sinon : retour PDF standard (téléchargement)
        response = HttpResponse(pdf_data, content_type='application/pdf')
        response['Content-Disposition'] = f'attachment; filename=Tonal_Devis_{current_sales_documents_id}.pdf'
        return response


    except Exception as e:
        return JsonResponse({'error': str(e)}, status=500)

def get_email_form_contacts_of_company(request):
    company_id = request.GET.get('company_id')

    if not company_id:
        return JsonResponse({'error': 'Missing company_id'}, status=400)

    company = models_companies.objects.filter(id_company=company_id).first()
    if not company:
        return JsonResponse({'error': 'Company not found'}, status=404)

    # Extrait les IDs de contact depuis le champ company_members_id (format ;0;id1;id2;)
    raw_ids = company.company_members_id or ''
    contact_ids = [cid for cid in raw_ids.strip(';').split(';') if cid and cid != '0']

    # Récupère les objets contact correspondants
    contacts = models_contacts.objects.filter(id_contact__in=contact_ids)

    data = [
        {
            'id': c.id_contact,
            'email': c.contact_email_1,
            'first_name': c.contact_first_name,
            'last_name': c.contact_last_name,
        }
        for c in contacts if c.contact_email_1
    ]

    return JsonResponse({'contacts': data})

def get_email_form_django_users(request):
    users = User.objects.filter(email__isnull=False).exclude(email="").order_by('last_name', 'first_name')

    data = [
        {
            'email': user.email,
            'first_name': user.first_name,
            'last_name': user.last_name
        }
        for user in users
    ]
    return JsonResponse({'users': data})


####################################################################################
#Mobile section redo all
def update_record_mobile(request, pk):

    if request.user.is_authenticated:

        #selectbox_all_companies = models_companies.objects.filter(company_members_id__icontains=";"+str(pk)+";")  # list all the companies where pk is a member of

        pk_format = str(';'+str(pk)+';')

        with connection.cursor() as cursor:

            # get all company_projects_id of all companies wher pk is member
            query_all_companies_where_pk_is_found = models_companies.objects.raw("SELECT * FROM table_companies WHERE company_members_id RLIKE '" + pk_format + "' ")
            selectbox_all_companies = [model_to_dict(l) for l in query_all_companies_where_pk_is_found]
            company_projects_ids_of_all_companies_where_pk_is_found = str([d['company_projects_id'] for d in selectbox_all_companies]).replace("[", '').replace("]",'').replace("'", '').replace("((",'').replace(",",'').replace(" ",'').replace("(",'').replace(")",'').replace(";;",';')

            # get the most recent project of company_projects_ids_of_all_companies_where_pk_is_found by filtering by date
            # supposed to be unique as all numbers are unique and a project cannot be attached to 2 different companies
            query_most_recent_project = models_projects.objects.raw(
                "SELECT * FROM table_projects WHERE '" + company_projects_ids_of_all_companies_where_pk_is_found + "' RLIKE CONCAT(';',id_project,';') ORDER by project_last_modification_date+0 DESC ")
            selectbox_projects = [model_to_dict(l) for l in query_most_recent_project]
            # if no project is present in the company, it sends back to the create new project which avec the ID 0
            if selectbox_projects == []:
                selectbox_most_recent_project = [{'id_project': '0', 'project_last_modification_date': '0', 'project_denomination': 'Comapany to save first'}] #'project_last_modification_date': '0' is mandatory
                formated_most_recent_project_id = str(';' + str([d['id_project'] for d in selectbox_most_recent_project]).replace("[", '').replace("]",'').replace("'", '') + ';')
            else:
                selectbox_most_recent_project = [selectbox_projects[0]]
                formated_most_recent_project_id = str(';'+str([d['id_project'] for d in selectbox_most_recent_project]).replace("[", '').replace("]",'').replace("'", '') +';')

            # get the company where the most recent project is attached
            # supposed to be unique as all numbers are unique and a project cannot be attached to 2 different companies
            query_most_recent_company = models_companies.objects.raw("SELECT * FROM table_companies WHERE company_projects_id RLIKE '" + formated_most_recent_project_id + "'")
            selectbox_most_recent_company = [model_to_dict(l) for l in query_most_recent_company]
            selectbox_most_recent_company_test = str([d['company_projects_id'] for d in selectbox_most_recent_company]).replace("[",'').replace("]",'').replace("'",'')
            selectbox_most_recent_company_members = str([d['company_members_id'] for d in selectbox_most_recent_company]).replace("[", '').replace("]",'').replace("'", '')
            selectbox_most_recent_company_members_id = str([d['id_company'] for d in selectbox_most_recent_company]).replace("[", '').replace("]",'').replace("'", '').replace(";",'')

            # all projects associates to the company where the most recent project is attached
            query_default_project = models_projects.objects.raw(
                "SELECT * FROM table_projects WHERE '" + selectbox_most_recent_company_test + "' RLIKE CONCAT(';',id_project,';') ORDER by project_last_modification_date+0 DESC ")  # used to be selectbox_projects_default
            selectbox_company_project = [model_to_dict(l) for l in query_default_project]
            # if no project is present in the company, it sends back to the create new project which have the ID 0
            if selectbox_company_project == []:
                selectbox_company_project = [
                    {'id_project': '0', 'project_last_modification_date': '0', 'project_denomination': 'Save company first'}] #'project_last_modification_date': '0' is mandatory

            ############################################################################################################

            # populate selectbox with all members of the 1st company found in the query above (number_of = company_members_id of first match found)
            query_selectbox_members = models_contacts.objects.raw(
                "SELECT * FROM table_contacts WHERE '" + selectbox_most_recent_company_members + "' RLIKE CONCAT(';',id_contact,';')")  # used to be selectbox_companies_default
            selectbox_members = [model_to_dict(l) for l in query_selectbox_members]
            selectbox_members = sorted(selectbox_members, key=lambda x: x['id_contact'] == '0')


            # Get default member by matching pk to populate selectbox
            query_default_selected_member = models_contacts.objects.raw(
                "SELECT * FROM table_contacts WHERE '" + pk_format + "' RLIKE CONCAT(';',id_contact,';')")
            default_selected_member = [model_to_dict(l) for l in query_default_selected_member]
            default_selected_member_id = str(
                [d['id_contact'] for d in default_selected_member]).replace("[", '').replace("]", '').replace("'",'').replace(";", '')

            if not selectbox_members:
                selectbox_members = default_selected_member

            # get the most recent project of company_projects_ids_of_all_companies_where_pk_is_found by filtering by date
            # cursor.execute(
            # "SELECT id_project FROM table_projects WHERE '" + company_projects_ids_of_all_companies_where_pk_is_found + "' RLIKE CONCAT(';',id_project,';') ORDER by project_last_modification_date+0 DESC ")
            # most_recent_project_id = cursor.fetchone()
            # formated_most_recent_project_id = str(';'+str(most_recent_project_id).replace("(",'').replace("(",'').replace(",",'').replace(")",'')+';')

            # find only one match of a company where pk is member to be able to search for all members of the company and populate select_box_members
            #cursor.execute("SELECT company_members_id FROM table_companies WHERE company_members_id RLIKE '"+pk_format + "' ") # list all the members whose pk is a member of
            #selectbox_companies_default = cursor.fetchone()
            #char_remov = [",", "(", ")","'"]
            #for char in char_remov:
                #selectbox_companies_default = str(str(selectbox_companies_default).replace(char, ''))

            # get company_projects_id of only the first matched company in the query selectbox_companies_default
            #cursor.execute("SELECT company_projects_id FROM table_companies WHERE company_members_id RLIKE '"+pk_format + "' ")
            #selectbox_projects_default = cursor.fetchone()
            #char_remov = [",", "(", ")", "'"]
            #for char in char_remov:
                #selectbox_projects_default = str(str(selectbox_projects_default).replace(char, ''))

        current_record = models_contacts.objects.get(id_contact=pk)
        current_record2 = models_projects.objects.get(id_project=formated_most_recent_project_id.replace(";",""))  # id= can be replace by any field on the DB
        # current_record3 = models_companies.objects.get(project_last_modification_date='202310041200') # id= can be replace by any field on the DB

        form = forms_contacts(request.POST or None, instance=current_record, pk=pk)
        form2 = forms_projects(request.POST or None, instance=current_record2)
        # form3 = forms_companies(request.POST or None, instance=current_record3)

        if form.is_valid():
            form.save()


        if form2.is_valid():
            form2.save()

        if form.is_valid() or form2.is_valid():
            return redirect('test')


        return render(request, 'update_record_mobile.html', {'form':form,
                                                             'form2': form2,
                                                             'selectbox_company_project':selectbox_company_project,
                                                             'selectbox_all_companies':selectbox_all_companies,
                                                             'selectbox_members':selectbox_members,
                                                             'default_selected_member_id':default_selected_member_id,
                                                             'selectbox_most_recent_company_members_id':selectbox_most_recent_company_members_id,
                                                             'formated_most_recent_project_id' : formated_most_recent_project_id.replace(";",""),
                                                             'selectbox_projects' : selectbox_projects,
                                                             'selectbox_most_recent_project':selectbox_most_recent_project
                                                             })
    else:
        messages.success(request, "You Must Be Logged In...")
        return redirect('home')

def article_filter_mobile(request):

    data = dict()
    search = request.POST.get('txtSearch')  # have to pass it also in Ajax
    select_main_search_prefilter = request.POST.get('select_main_search_prefilter')  # have to pass it also in Ajax





    if not search == "":
        if select_main_search_prefilter == "name":
            locations = models_contacts.objects.raw("SELECT * FROM table_contacts "
                                         "WHERE "
                                         "contact_first_name RLIKE %s OR "
                                         "contact_last_name RLIKE %s",
                                                    [search,search])
            main_searched_contact_found = [model_to_dict(l) for l in locations]
            main_searched_contact_found = [l for l in main_searched_contact_found if l['id_contact'] != '0']

            # get all companies name and company_memberd_id
            query_all_companies_name = models_companies.objects.raw("SELECT * FROM table_companies ")
            all_companies_name = [model_to_dict(l) for l in query_all_companies_name]
            # reorganise all_companies_name list
            companies = {}
            for d in all_companies_name:
                for i in d.get('company_members_id', '').strip(';').split(';'):
                    companies.setdefault(i, []).append(d['company_name'])
            companies = {i: ' ; '.join(v) for i, v in companies.items()}
            # it gives :
            # {'1': 'Nike;Adidas', '3': 'Nike', '4': 'Nike', '11': 'Nike',
            #  '2': 'Adidas', '9': 'Adidas'}

            # create and populate company_name in main_searched_contact_found to have société in jqgrid
            for d in main_searched_contact_found:
                if companies.get(d['id_contact']) == None:
                    d['company_name'] = ' '
                else:
                    d['company_name'] = companies.get(d['id_contact'])

            #return render(request, 'grid.html', {'main_searched_contact_found': main_searched_contact_found})
            #return JsonResponse(list_of_dicts, safe=False)
            data['html_table'] = render_to_string('grid_mobile.html', {'main_searched_contact_found': main_searched_contact_found},
                                                  request=request)
            return JsonResponse(data)
        if select_main_search_prefilter == "everywhere":
            with connection.cursor() as cursor:

                # Search match in table projects and retrieve id of project .....
                cursor.execute(
                    "SELECT id_project FROM table_projects WHERE "
                    "id_project RLIKE '" + search + "'"
                    " OR project_last_modification_date RLIKE '" + search + "'"
                    " OR project_denomination RLIKE '" + search + "' ")
                curs_number_of_2 = cursor.fetchall()
                number_of_2 = []
                for x in curs_number_of_2:
                    number_of_2.append(x[0])
                number_of_2 = str(number_of_2).replace(',','|').replace(' ','').replace('[','').replace(']','')
                # ... to search match in contact_table + find company where project is linked to include the contacts involved ...
                cursor.execute(
                    "SELECT company_members_id FROM table_companies WHERE id_company RLIKE '" + search + "'"
                    " OR company_name RLIKE '" + search + "'"
                     " OR company_members_id RLIKE '" + search + "'"
                     " OR company_projects_id RLIKE '" + search + "'"
                     " OR company_projects_id RLIKE ';("+number_of_2+");'")
                number_of_11 = cursor.fetchall()
                number_of = []
                for x in number_of_11:
                    number_of.append(x[0])
                number_of = str(number_of).replace(',','').replace('(','').replace(')','').replace("'",'').replace(' ','').replace('[','').replace(']','').replace(';;',';')


                # ... to finally search matches + ids found in companies_table and projects_table

            locations = models_contacts.objects.raw("SELECT * FROM table_contacts WHERE "
                                        "id_contact RLIKE '" + search + "' OR "
                                          "'"+number_of+"' RLIKE CONCAT(';',id_contact,';') OR "
                                          "contact_first_name RLIKE '" + search + "' OR "
                                          "contact_last_name RLIKE '" + search + "' OR "
                                          "contact_email_1 RLIKE '" + search + "' OR "
                                          "contact_phone_1 RLIKE '" + search + "' OR "
                                          "contact_phone_2 RLIKE '" + search + "' OR "
                                          "contact_email_2 RLIKE '" + search + "' OR "
                                          "contact_gender RLIKE '" + search + "' OR "
                                          "contact_language RLIKE '" + search + "' OR "
                                          "test RLIKE '" + search + "' ")


            main_searched_contact_found = [model_to_dict(l) for l in locations]
            main_searched_contact_found = [l for l in main_searched_contact_found if l['id_contact'] != '0']

            # get all companies name and company_memberd_id
            query_all_companies_name = models_companies.objects.raw("SELECT * FROM table_companies ")
            all_companies_name = [model_to_dict(l) for l in query_all_companies_name]
            # reorganise all_companies_name list
            companies = {}
            for d in all_companies_name:
                for i in d.get('company_members_id', '').strip(';').split(';'):
                    companies.setdefault(i, []).append(d['company_name'])
            companies = {i: ' ; '.join(v) for i, v in companies.items()}
            #it gives :
            # {'1': 'Nike;Adidas', '3': 'Nike', '4': 'Nike', '11': 'Nike','2': 'Adidas', '9': 'Adidas'}

            # create and populate company_name in main_searched_contact_found to have société in jqgrid
            for d in main_searched_contact_found:
                if companies.get(d['id_contact']) == None:
                    d['company_name'] = ' '
                else:
                    d['company_name'] = companies.get(d['id_contact'])

            #return render(request, 'grid.html', {'main_searched_contact_found': main_searched_contact_found})
            # return JsonResponse(list_of_dicts, safe=False)
            data['html_table'] = render_to_string('grid_mobile.html', {'main_searched_contact_found': main_searched_contact_found,'number_of':number_of, 'all_companies_name':all_companies_name},request=request)
            return JsonResponse(data)
    else:
        locations = models_contacts.objects.raw("SELECT * FROM table_contacts")
        main_searched_contact_found = [model_to_dict(l) for l in locations]
        main_searched_contact_found = [l for l in main_searched_contact_found if l['id_contact'] != '0']

        # get all companies name and company_memberd_id
        query_all_companies_name = models_companies.objects.raw("SELECT * FROM table_companies ")
        all_companies_name = [model_to_dict(l) for l in query_all_companies_name]
        # reorganise all_companies_name list
        companies = {}
        for d in all_companies_name:
            for i in d.get('company_members_id', '').strip(';').split(';'):
                companies.setdefault(i, []).append(d['company_name'])
        companies = {i: ' ; '.join(v) for i, v in companies.items()}
        # it gives :
        # {'1': 'Nike;Adidas', '3': 'Nike', '4': 'Nike', '11': 'Nike',
        #  '2': 'Adidas', '9': 'Adidas'}

        # create and populate company_name in main_searched_contact_found to have société in jqgrid
        for d in main_searched_contact_found:
            if companies.get(d['id_contact']) == None:
                d['company_name'] = ' '
            else:
                d['company_name'] = companies.get(d['id_contact'])

        data['html_table'] = render_to_string('grid_mobile.html', {'main_searched_contact_found': main_searched_contact_found},request=request)


        return JsonResponse(data)

####################################################################################
#Grid main search section
def main_search_records(request):
    data = dict()

    search = request.POST.get('txtSearch')
    select_main_search_prefilter = request.POST.get('select_main_search_prefilter')

    if search:
        if select_main_search_prefilter == "name":
            main_searched_contact_found_query = models_contacts.objects.filter(Q(contact_first_name__icontains=search) | Q(contact_last_name__icontains=search))
            main_searched_contact_found = [model_to_dict(l) for l in main_searched_contact_found_query]
            main_searched_contact_found = [l for l in main_searched_contact_found if str(l['id_contact']) != '0']

            data['html_table'] = render_to_string('grid.html',{'main_searched_contact_found': main_searched_contact_found,
                                                               'main_searched_company_found': [],
                                                               },
                                                  request=request)
            return JsonResponse(data)

        elif select_main_search_prefilter == "company_name":
            main_searched_company_found_query = models_companies.objects.filter(
                company_name__icontains=search
            )
            main_searched_company_found = [model_to_dict(l) for l in main_searched_company_found_query]
            main_searched_company_found = [l for l in main_searched_company_found if str(l['id_company']) != '0']

            data['html_table'] = render_to_string('grid.html',{'main_searched_contact_found': [],
                                                               'main_searched_company_found': main_searched_company_found,
                                                               },
                                                  request=request)
            return JsonResponse(data)

        elif select_main_search_prefilter == "everywhere":
            main_searched_contact_found_query = models_contacts.objects.filter(
                Q(id_contact__icontains=search) |
                Q(contact_first_name__icontains=search) |
                Q(contact_last_name__icontains=search) |
                Q(contact_email_1__icontains=search) |
                Q(contact_phone_1__icontains=search) |
                Q(contact_email_2__icontains=search) |
                Q(contact_phone_2__icontains=search) |
                Q(contact_gender__icontains=search) |
                Q(contact_language__icontains=search) |
                Q(test__icontains=search)
            )
            main_searched_company_found_query = models_companies.objects.filter(
                Q(id_company__icontains=search) |
                Q(company_name__icontains=search) |
                Q(company_members_id__icontains=search)
            )

            main_searched_project_found_query = models_projects.objects.filter(
                Q(id_project__icontains=search) |
                Q(project_last_modification_date__icontains=search) |
                Q(project_denomination__icontains=search) |
                Q(project_sales_document__icontains=search)
            )

            main_searched_interaction_found_query = models_interactions.objects.filter(
                Q(id_interaction__icontains=search) |
                Q(interaction_full_date__icontains=search) |
                Q(interaction_date__icontains=search) |
                Q(interaction_time__icontains=search) |
                Q(interaction_user__icontains=search) |
                Q(interaction_contact_id__icontains=search) |
                Q(interaction_company_id__icontains=search) |
                Q(interaction_project_id__icontains=search) |
                Q(interaction_content__icontains=search) |
                Q(interaction_type__icontains=search) |
                Q(interaction_mode__icontains=search)
            )

            main_searched_contact_found = [model_to_dict(l) for l in main_searched_contact_found_query]
            main_searched_contact_found = [l for l in main_searched_contact_found if l['id_contact'] != '0'] #comparison to 0 not working if DB format is auto implemented number. VARCHAR works

            main_searched_company_found = [model_to_dict(l) for l in main_searched_company_found_query]
            main_searched_company_found = [l for l in main_searched_company_found if l['id_company'] != '0']

            main_searched_project_found = [model_to_dict(l) for l in main_searched_project_found_query]
            main_searched_project_found = [l for l in main_searched_project_found if l['id_project'] != '0']

            main_searched_interaction_found = [model_to_dict(l) for l in main_searched_interaction_found_query]
            main_searched_interaction_found = [l for l in main_searched_interaction_found if l['id_interaction'] != '0']

            data['html_table'] = render_to_string('grid.html', {'main_searched_contact_found': main_searched_contact_found,
                                                            'main_searched_company_found': main_searched_company_found,
                                                            'main_searched_project_found': main_searched_project_found,
                                                            'main_searched_interaction_found': main_searched_interaction_found,
                                                            },
                                                  request=request)
            return JsonResponse(data)
    else:
        main_searched_contact_found_query = models_contacts.objects.all()
        main_searched_company_found_query = models_companies.objects.all()
        main_searched_project_found_query = models_projects.objects.all()
        main_searched_interaction_found_query = models_interactions.objects.all()

        main_searched_contact_found = [model_to_dict(l) for l in main_searched_contact_found_query]
        main_searched_contact_found = [l for l in main_searched_contact_found if l['id_contact'] != '0'] #comparison to 0 not working if DB format is auto implemented number. VARCHAR works

        main_searched_company_found = [model_to_dict(l) for l in main_searched_company_found_query]
        main_searched_company_found = [l for l in main_searched_company_found if l['id_company'] != '0']

        main_searched_project_found = [model_to_dict(l) for l in main_searched_project_found_query]
        main_searched_project_found = [l for l in main_searched_project_found if l['id_project'] != '0']

        main_searched_interaction_found = [model_to_dict(l) for l in main_searched_interaction_found_query]
        main_searched_interaction_found = [l for l in main_searched_interaction_found if l['id_interaction'] != '0']

        data['html_table'] = render_to_string('grid.html', {'main_searched_contact_found': main_searched_contact_found,
                                                            'main_searched_company_found': main_searched_company_found,
                                                            'main_searched_project_found': main_searched_project_found,
                                                            'main_searched_interaction_found': main_searched_interaction_found,
                                                            },
                                              request=request)


        return JsonResponse(data)

def search_contact_relations(request):
    data = dict()

    selected_rows_in_grid = request.POST.get('selected_rows')
    if not selected_rows_in_grid :
        selected_rows_in_grid = '00'
    selected_rows_in_grid = selected_rows_in_grid.split("%")
    selected_rows_in_grid = [x for x in selected_rows_in_grid if x]

    # Company
    company_clauses = (Q(company_members_id__contains=x) for x in selected_rows_in_grid) #must be in format like selected_rows_in_grid = [';1;',';11;']
    company_query = reduce(operator.or_, company_clauses)
    company_filter = models_companies.objects.filter(company_query)
    company_relations = [model_to_dict(l) for l in company_filter]
    company_relations = [l for l in company_relations if l['id_company'] != '0']#comparison to 0 not working if DB format is auto implemented number. VARCHAR works

    # Project
    get_all_projects_id = [x['company_projects_id'] for x in company_relations]
    get_all_projects_id = ''.join(get_all_projects_id).split(";")
    get_all_projects_id = [x for x in get_all_projects_id if x] # remove blank
    #get_all_projects_id = re.sub("\;+", ";", get_all_projects_id)
    project_filter = models_projects.objects.filter(id_project__in=get_all_projects_id)
    project_relations = [model_to_dict(l) for l in project_filter]
    project_relations = [l for l in project_relations if l['id_project'] != '0']#comparison to 0 not working if DB format is auto implemented number. VARCHAR works

    # Interaction
    selected_rows_in_grid = [x.replace(';', '') for x in selected_rows_in_grid if x]
    interaction_filter = models_interactions.objects.filter(interaction_contact_id__in=selected_rows_in_grid)
    interaction_relations = [model_to_dict(l) for l in interaction_filter]
    interaction_relations = [l for l in interaction_relations if l['id_interaction'] != '0']#comparison to 0 not working if DB format is auto implemented number. VARCHAR works

    data['html_table'] = render_to_string('sub_grid.html', {'company_relations': company_relations,
                                                            'interaction_relations':interaction_relations,
                                                            'project_relations':project_relations,
                                                            },
                                          request=request)
    return JsonResponse(data)

def search_company_relations(request):
    data = dict()

    selected_rows_in_grid = request.POST.get('selected_rows')
    if not selected_rows_in_grid:
        selected_rows_in_grid = '00'
    selected_rows_in_grid = selected_rows_in_grid.split("%")
    selected_rows_in_grid = [x.replace(';', '') for x in selected_rows_in_grid if x]

    # Company
    company_filter = models_companies.objects.filter(id_company__in=selected_rows_in_grid)
    company_relations = [model_to_dict(l) for l in company_filter]
    company_relations = [l for l in company_relations if l['id_company'] != '0']

    # Contact
    get_all_contacts_id = [x['company_members_id'] for x in company_relations]
    get_all_contacts_id = ''.join(get_all_contacts_id).split(";")
    get_all_contacts_id = [x for x in get_all_contacts_id if x] # remove blank
    #get_all_contacts_id = re.sub("\;+", ";", get_all_contacts_id)
    contact_filter = models_contacts.objects.filter(id_contact__in=get_all_contacts_id)
    contact_relations = [model_to_dict(l) for l in contact_filter]
    contact_relations = [l for l in contact_relations if l['id_contact'] != '0']  # comparison to 0 not working if DB format is auto implemented number. VARCHAR works

    # Project
    get_all_projects_id = [x['company_projects_id'] for x in company_relations]
    get_all_projects_id = ''.join(get_all_projects_id).split(";")
    get_all_projects_id = [x for x in get_all_projects_id if x] #remove blank
    #get_all_projects_id = re.sub("\;+", ";", get_all_projects_id)
    project_filter = models_projects.objects.filter(id_project__in=get_all_projects_id)
    project_relations = [model_to_dict(l) for l in project_filter]
    project_relations = [l for l in project_relations if l['id_project'] != '0']  # comparison to 0 not working if DB format is auto implemented number. VARCHAR works

    # Interaction
    interaction_query = Q()
    for company_id in selected_rows_in_grid:
        interaction_query |= Q(interaction_company_id__icontains=f';{company_id};')
    interaction_filter = models_interactions.objects.filter(interaction_query)
    interaction_relations = [model_to_dict(l) for l in interaction_filter]
    interaction_relations = [l for l in interaction_relations if l['id_interaction'] != '0']  # comparison to 0 not working if DB format is auto implemented number. VARCHAR works

    data['html_table'] = render_to_string('sub_grid.html', {'contact_relations':contact_relations,
                                                            'company_relations':company_relations,
                                                            'project_relations': project_relations,
                                                            'interaction_relations':interaction_relations,
                                                            },
                                          request=request)
    return JsonResponse(data)

def search_project_relations(request):
    data = dict()

    selected_rows_in_grid = request.POST.get('selected_rows')
    if not selected_rows_in_grid :
        selected_rows_in_grid = '00'
    selected_rows_in_grid = selected_rows_in_grid.split("%")
    selected_rows_in_grid = [x for x in selected_rows_in_grid if x]

    # Company
    company_clauses = (Q(company_projects_id__contains=x) for x in selected_rows_in_grid) #must be in format like selected_rows_in_grid = [';1;',';11;']
    company_query = reduce(operator.or_, company_clauses)
    company_filter = models_companies.objects.filter(company_query)
    company_relations = [model_to_dict(l) for l in company_filter]
    company_relations = [l for l in company_relations if l['id_company'] != '0']#comparison to 0 not working if DB format is auto implemented number. VARCHAR works

    # Contact
    get_all_contacts_id = [x['company_members_id'] for x in company_relations]
    get_all_contacts_id = ''.join(get_all_contacts_id).split(";")
    get_all_contacts_id = [x for x in get_all_contacts_id if x]  # remove blank
    # get_all_contacts_id = re.sub("\;+", ";", get_all_contacts_id)
    contact_filter = models_contacts.objects.filter(id_contact__in=get_all_contacts_id)
    contact_relations = [model_to_dict(l) for l in contact_filter]
    contact_relations = [l for l in contact_relations if l['id_contact'] != '0']  # comparison to 0 not working if DB format is auto implemented number. VARCHAR works

    # Interaction
    selected_rows_in_grid = [x.replace(';', '') for x in selected_rows_in_grid if x]
    interaction_filter = models_interactions.objects.filter(interaction_project_id__in=selected_rows_in_grid)
    interaction_relations = [model_to_dict(l) for l in interaction_filter]
    interaction_relations = [l for l in interaction_relations if l['id_interaction'] != '0']#comparison to 0 not working if DB format is auto implemented number. VARCHAR works

    data['html_table'] = render_to_string('sub_grid.html', {'company_relations': company_relations,
                                                            'interaction_relations':interaction_relations,
                                                            'contact_relations':contact_relations,
                                                            },
                                          request=request)
    return JsonResponse(data)

def search_interaction_relations(request):

    data = dict()

    selected_rows_in_grid = request.POST.get('selected_rows')
    if not selected_rows_in_grid:
        selected_rows_in_grid = '00'
    selected_rows_in_grid = selected_rows_in_grid.split("%")
    selected_rows_in_grid = [x.replace(';', '') for x in selected_rows_in_grid if x]

    # Interaction
    interaction_filter = models_interactions.objects.filter(id_interaction__in=selected_rows_in_grid)
    interaction_relations = [model_to_dict(l) for l in interaction_filter]
    interaction_relations = [l for l in interaction_relations if l['id_interaction'] != '0']  # comparison to 0 not working if DB format is auto implemented number. VARCHAR works

    # Contact
    get_all_contacts_id = [x['interaction_contact_id'] for x in interaction_relations]
    #get_all_contacts_id = ''.join(get_all_contacts_id).split(";")
    get_all_contacts_id = [x for x in get_all_contacts_id if x]  # remove blank
    # get_all_contacts_id = re.sub("\;+", ";", get_all_contacts_id)
    contact_filter = models_contacts.objects.filter(id_contact__in=get_all_contacts_id)
    contact_relations = [model_to_dict(l) for l in contact_filter]
    contact_relations = [l for l in contact_relations if l['id_contact'] != '0']  # comparison to 0 not working if DB format is auto implemented number. VARCHAR works

    # Company
    get_all_company_id_raw = [x['interaction_company_id'] for x in interaction_relations]
    get_all_company_id = []
    for entry in get_all_company_id_raw:
        # Exemple : ";2025050110270074;2025050122175666;"
        split_ids = entry.strip(';').split(';') if entry else []
        get_all_company_id.extend(split_ids)
    # Supprimer les doublons et valeurs vides
    get_all_company_id = list(set(filter(None, get_all_company_id)))
    company_filter = models_companies.objects.filter(id_company__in=get_all_company_id)
    company_relations = [model_to_dict(l) for l in company_filter]
    company_relations = [l for l in company_relations if l['id_company'] != '0']


    # Project
    get_all_projects_id = [x['interaction_project_id'] for x in interaction_relations]
    #get_all_projects_id = ''.join(get_all_projects_id).split(";")
    get_all_projects_id = [x for x in get_all_projects_id if x] #remove blank
    #get_all_projects_id = re.sub("\;+", ";", get_all_projects_id)
    project_filter = models_projects.objects.filter(id_project__in=get_all_projects_id)
    project_relations = [model_to_dict(l) for l in project_filter]
    project_relations = [l for l in project_relations if l['id_project'] != '0']  # comparison to 0 not working if DB format is auto implemented number. VARCHAR works

    data['html_table'] = render_to_string('sub_grid.html', {'contact_relations':contact_relations,
                                                            'company_relations':company_relations,
                                                            'project_relations': project_relations,
                                                            'interaction_relations':interaction_relations,
                                                            'selected_rows_in_grid': selected_rows_in_grid,
                                                            },
                                          request=request)
    return JsonResponse(data)

####################################################################################

def home(request):
    user_agent = get_user_agent(request)


    if user_agent.is_pc:

        records = models_contacts.objects.all()
        # Check to see if logging in
        if request.method == 'POST':
            username = request.POST['username']
            password = request.POST['password']
            # Authenticate
            user = authenticate(request, username=username, password=password)
            if user is not None:
                login(request, user)
                messages.success(request, "You Have Been Logged In PC!")
                return redirect('home')
            else:
                messages.success(request, "There Was An Error Logging In, Please Try Again...")
                return redirect('home')
        else:
            return render(request, 'home.html', {'records':records})

    elif user_agent.is_mobile:

        records = models_contacts.objects.all()
        # Check to see if logging in
        if request.method == 'POST':
            username = request.POST['username']
            password = request.POST['password']
            # Authenticate
            user = authenticate(request, username=username, password=password)
            if user is not None:
                login(request, user)
                messages.success(request, "You Have Been Logged In MOBILE!")
                return redirect('test')
            else:
                messages.success(request, "There Was An Error Logging In, Please Try Again...")
                return redirect('test')
        else:
            return render(request, 'test.html', {'records': records})

def logout_user(request):
    logout(request)
    messages.success(request, "You Have Been Logged Out...")
    return redirect('home')

def register_user(request):
    if request.method == 'POST':
        form = SignUpForm(request.POST)
        if form.is_valid():
            form.save()
            # Authenticate and login
            username = form.cleaned_data['username']
            password = form.cleaned_data['password1']
            user = authenticate(username=username, password=password)
            login(request, user)
            messages.success(request, "You Have Successfully Registered! Welcome!")
            return redirect('home')
    else:
        form = SignUpForm()
        return render(request, 'register.html', {'form':form})

    return render(request, 'register.html', {'form':form})

def customer_record(request, pk):
    if request.user.is_authenticated:
        # Look Up Records
        customer_record = models_contacts.objects.get(id_contact=pk)
        return render(request, 'record.html', {'customer_record':customer_record})
    else:
        messages.success(request, "You Must Be Logged In To View That Page...")
        return redirect('home')

def delete_record(request, pk):
    if request.user.is_authenticated:
        delete_it = models_contacts.objects.get(id_contact=pk)
        delete_it.delete()
        messages.success(request, "Record Deleted Successfully...")
        return redirect('home')
    else:
        messages.success(request, "You Must Be Logged In To Do That...")
        return redirect('home')

def add_record(request):
    if request.user.is_authenticated:

        form = forms_add_contacts(request.POST or None)
        form2 = forms_companies(request.POST or None)

        if request.method == "POST":
            if form.is_valid():
                form.save()
                form2.save()
                messages.success(request, "Record Added...")
                return redirect('home')
        return render(request, 'add_record.html', {'form':form,'form2':form2})
    else:
        messages.success(request, "You Must Be Logged In...")
        return redirect('home')

def add_or_remove_existing_contact_to_current_company(request):

    add_or_remove = request.POST.get('add_or_remove')
    existing_contact_id = request.POST.get('existing_contact_id')
    current_company = request.POST.get('current_company')

    current_company_members_id_value = models_companies.objects.filter(id_company=current_company).values_list('company_members_id', flat=True)
    if add_or_remove == "add":
        if ';'+existing_contact_id+';' not in current_company_members_id_value[0]:

            current_company_members_id = models_companies.objects.get(id_company=current_company)

            if current_company_members_id_value[0] == '':
                current_company_members_id.company_members_id = ';0;' + existing_contact_id + ';' # change field
            else:
                current_company_members_id.company_members_id = current_company_members_id_value[0]+existing_contact_id+';' # change field

            current_company_members_id.save()  # this will update only

            result_2 = 'Contact added to company !'
            return JsonResponse({"result_2": result_2})

        else:
            result_2 = 'existe deja'
            return JsonResponse({"result_2": result_2})
    if add_or_remove == "remove":

        if ';' + existing_contact_id + ';' in current_company_members_id_value[0]:

            current_company_members_id = models_companies.objects.get(id_company=current_company)
            current_company_members_id.company_members_id = current_company_members_id_value[0].replace(existing_contact_id + ';', '')  # change field
            current_company_members_id.save()  # this will update only

            result_2 = 'Contact removed from company !'
            return JsonResponse({"result_2":result_2})

        else:
            result_2 = 'Not a member of the currrent company'
            return JsonResponse({"result_2": result_2})

####################################################################################
def update_selectbox_sales_documents_edit(request):
    if request.user.is_authenticated:
        project_num = request.GET.get('project_num')

        list_sales_documents = list(
            item.project_sales_document for item in models_projects.objects.filter(id_project=project_num)
        )

        list_sales_documents = str(list_sales_documents).split(';')[1:-1]

        sales_documents_qs = models_sales_documents.objects.filter(id_sales_documents__in=list_sales_documents)

        documents = []

        for doc in sales_documents_qs:
            invoice_id = (doc.sales_documents_invoice_id or '').strip()
            delivery_note_id = (getattr(doc, 'sales_documents_delivery_note_id', '') or '').strip()
            purchase_order_id = (doc.sales_documents_purchase_order_id or '').strip()
            quote_id = (doc.sales_documents_quote_id or '').strip()
            invoice_number = (doc.sales_documents_invoice_number or '').strip()
            delivery_note_number = (getattr(doc, 'sales_documents_delivery_note_number', '') or '').strip()
            purchase_order_number = (doc.sales_documents_purchase_order_number or '').strip()
            quote_number = (doc.sales_documents_quote_number or '').strip()

            timeline_step = (doc.sales_documents_timeline_step or '').strip()

            doc_types = []
            if timeline_step == 'invoice':
                doc_types.append("invoice")
                doc_types.append("delivery_note")
                doc_types.append("deposit")
                doc_types.append("quote")

            if timeline_step == 'delivery_note':
                doc_types.append("delivery_note")
                doc_types.append("deposit")
                doc_types.append("quote")

            if timeline_step == 'deposit':
                doc_types.append("deposit")
                doc_types.append("quote")

            if timeline_step == 'quote':
                doc_types.append("quote")


            if not doc_types:
                doc_types.append("quote")

            if "invoice" in doc_types:
                main_type = "invoice"
            elif "delivery_note" in doc_types:
                main_type = "delivery_note"
            elif "deposit" in doc_types:
                main_type = "deposit"
            else:
                main_type = "quote"

            # ✅ Conversion de l'étape en texte avec fallback
            valid_steps = ['quote', 'deposit', 'delivery_note', 'invoice']
            step_raw = str(doc.sales_documents_timeline_step or '').strip().lower()
            step = step_raw if step_raw in valid_steps else 'quote'

            # Format de retour JSON
            documents.append({
                "id": doc.id_sales_documents,
                "denomination": doc.sales_documents_denomination,
                "last_mod": doc.sales_documents_last_modification_date,
                "invoice_id" : invoice_id,
                "delivery_note_id" : delivery_note_id,
                "purchase_order_id" : purchase_order_id,
                "quote_id" : quote_id,
                "invoice_number": invoice_number,
                "delivery_note_number": delivery_note_number,
                "purchase_order_number": purchase_order_number,
                "quote_number": quote_number,
                "types": doc_types,
                "main_type": main_type,
                "step": step,  # ✅ pour timeline
                "deposit_id": doc.sales_documents_deposit_id or '',
                "deposit_number": doc.sales_documents_deposit_number or '',
                "deposit_date": doc.sales_documents_deposit_date or '',
                "deposit_amount": doc.sales_documents_deposit_amount or '',
                "deposit_method": doc.sales_documents_deposit_method or '',
                "rent_or_sale": doc.sales_documents_rent_or_sale or''
            })

        documents_sorted = sorted(documents, key=lambda x: x['last_mod'], reverse=True)

        return JsonResponse({
            "documents": documents_sorted
        })

    else:
        messages.success(request, "You Must Be Logged In...")
        return redirect('home')

def save_deposit_info(request):
    if not request.user.is_authenticated or request.method != 'POST':
        return JsonResponse({"error": "unauthorized"}, status=403)

    doc_id = request.POST.get("doc_id")
    new_id = (request.POST.get("deposit_id") or '0').strip()
    new_number = (request.POST.get("deposit_number") or '0').strip()
    new_date = (request.POST.get("deposit_date") or '0').strip()
    new_amount = (request.POST.get("deposit_amount") or '0').strip()
    new_method = (request.POST.get("deposit_method") or '0').strip()

    try:
        doc = models_sales_documents.objects.get(id_sales_documents=doc_id)

        # Nettoyage
        def split_clean(field):
            return [s.strip() for s in (field or '').split(';') if s.strip()]

        ids = split_clean(doc.sales_documents_deposit_id)
        numbers = split_clean(doc.sales_documents_deposit_number)
        dates = split_clean(doc.sales_documents_deposit_date)
        amounts = split_clean(doc.sales_documents_deposit_amount)
        methods = split_clean(doc.sales_documents_deposit_method)

        # Recherche index d'un ID déjà existant
        try:
            idx = ids.index(new_id)
            numbers[idx] = new_number
            dates[idx] = new_date
            amounts[idx] = new_amount
            methods[idx] = new_method
        except ValueError:
            # ID non présent → ajout
            ids.append(new_id)
            numbers.append(new_number)
            dates.append(new_date)
            amounts.append(new_amount)
            methods.append(new_method)

        # Reconstruire les chaînes format ;a;b;c;
        def join_with_semi(values):
            return ';' + ';'.join(values) + ';' if values else ''

        doc.sales_documents_deposit_id = join_with_semi(ids)
        doc.sales_documents_deposit_number = join_with_semi(numbers)
        doc.sales_documents_deposit_date = join_with_semi(dates)
        doc.sales_documents_deposit_amount = join_with_semi(amounts)
        doc.sales_documents_deposit_method = join_with_semi(methods)

        doc.save()
        return JsonResponse({"success": True})
    except models_sales_documents.DoesNotExist:
        return JsonResponse({"error": "Document introuvable"}, status=404)

def delete_deposit_info(request):
    if not request.user.is_authenticated or request.method != "POST":
        return JsonResponse({"error": "unauthorized"}, status=403)

    doc_id = request.POST.get("doc_id")
    deposit_id_to_remove = request.POST.get("deposit_id")

    try:
        doc = models_sales_documents.objects.get(id_sales_documents=doc_id)

        def clean_and_filter(field_value):
            return [v for v in (field_value or '').split(';') if v]

        ids = clean_and_filter(doc.sales_documents_deposit_id)
        numbers = clean_and_filter(doc.sales_documents_deposit_number)
        dates = clean_and_filter(doc.sales_documents_deposit_date)
        amounts = clean_and_filter(doc.sales_documents_deposit_amount)
        methods = clean_and_filter(doc.sales_documents_deposit_method)

        try:
            index_to_remove = ids.index(deposit_id_to_remove)
        except ValueError:
            return JsonResponse({"error": "ID non trouvé"}, status=404)

        # Supprimer les éléments à l’index trouvé
        ids.pop(index_to_remove)
        numbers.pop(index_to_remove) if len(numbers) > index_to_remove else None
        dates.pop(index_to_remove) if len(dates) > index_to_remove else None
        amounts.pop(index_to_remove) if len(amounts) > index_to_remove else None
        methods.pop(index_to_remove) if len(methods) > index_to_remove else None

        # Réassembler les strings
        doc.sales_documents_deposit_id = ';' + ';'.join(ids) + ';' if ids else ''
        doc.sales_documents_deposit_number = ';' + ';'.join(numbers) + ';' if numbers else ''
        doc.sales_documents_deposit_date = ';' + ';'.join(dates) + ';' if dates else ''
        doc.sales_documents_deposit_amount = ';' + ';'.join(amounts) + ';' if amounts else ''
        doc.sales_documents_deposit_method = ';' + ';'.join(methods) + ';' if methods else ''

        doc.save()
        return JsonResponse({"success": True})
    except models_sales_documents.DoesNotExist:
        return JsonResponse({"error": "Document introuvable"}, status=404)


@never_cache # evite le rechargement en cache, sinon quand on refresh la page certaines données ne sont pas actualisé (par exemple le dernier projet modifié)
def update_record(request, pk):
    #in the futur, get rid of the ';' by first query all company_members_id, creating a list with ',' and then search pk_format without ';', see examples in search_contact_relations()

    if request.user.is_authenticated:
        pk_format = str(';' + str(pk) + ';')

        with connection.cursor() as cursor:

            # get all company_projects_id of all companies where pk is member
            query_all_companies_where_pk_is_found = models_companies.objects.filter(Q(company_members_id__icontains=pk_format) | Q(id_company='0'))
            # Conversion en dictionnaire
            selectbox_all_companies = [model_to_dict(company) for company in query_all_companies_where_pk_is_found]
            # Tri : mettre les 'id_company' == '0' à la fin
            selectbox_all_companies = sorted(selectbox_all_companies, key=lambda x: x['id_company'] == '0')
            # Extraction et nettoyage des 'company_projects_id'
            company_projects_ids_of_all_companies_where_pk_is_found = ";".join(
                str(d['company_projects_id']) for d in selectbox_all_companies if d['company_projects_id']
            ).replace(";;", ";")

            # get the most recent project of company_projects_ids_of_all_companies_where_pk_is_found by filtering by date
            # supposed to be unique as all numbers are unique and a project cannot be attached to 2 different companies
            project_ids = company_projects_ids_of_all_companies_where_pk_is_found.strip(";").split(";")

            query_most_recent_project = models_projects.objects.filter(id_project__in=project_ids).order_by('-project_last_modification_date')

            selectbox_projects = [model_to_dict(l) for l in query_most_recent_project]
            # if no project is present in the company, it sends back to the create new project which has the ID 0
            if selectbox_projects == []:
                selectbox_most_recent_project = [{'id_project': '0', 'project_last_modification_date': '0', 'project_denomination': 'plz save company first'}]  # 'project_last_modification_date': '0' is mandatory
                formated_most_recent_project_id = str(';' + str([d['id_project'] for d in selectbox_most_recent_project]).replace("[", '').replace("]", '').replace("'", '') + ';')
            else:
                selectbox_most_recent_project = [selectbox_projects[0]]
                formated_most_recent_project_id = str(';' + str([d['id_project'] for d in selectbox_most_recent_project]).replace("[", '').replace("]", '').replace("'", '') + ';')

            # get the company where the most recent project is attached
            # supposed to be unique as all numbers are unique and a project cannot be attached to 2 different companies
            query_most_recent_company = models_companies.objects.filter(
                Q(company_projects_id__icontains=formated_most_recent_project_id),
                Q(company_members_id__icontains=pk_format)
            )

            selectbox_most_recent_company = [model_to_dict(l) for l in query_most_recent_company]

            selectbox_most_recent_company_test = str([d['company_projects_id'] for d in selectbox_most_recent_company]).replace("[", '').replace("]", '').replace("'", '')
            selectbox_most_recent_company_members = str([d['company_members_id'] for d in selectbox_most_recent_company]).replace("[", '').replace("]", '').replace("'", '')
            selectbox_most_recent_company_members_id = str([d['id_company'] for d in selectbox_most_recent_company]).replace("[", '').replace("]", '').replace("'", '').replace(";", '')

            # all projects associated to the company where the most recent project is attached
            company_project_ids = selectbox_most_recent_company_test.strip(";").split(";")

            query_default_project = models_projects.objects.filter(
                id_project__in=company_project_ids
            ).order_by('-project_last_modification_date')

            selectbox_company_project = [model_to_dict(l) for l in query_default_project]
            # if no project is present in the company, it sends back to the create new project which has the ID 0
            if selectbox_company_project == []:
                selectbox_company_project = [{'id_project': '0', 'project_last_modification_date': '0', 'project_denomination': 'Seva company first'}]  # 'project_last_modification_date': '0' is mandatory

            ############################################################################################################

            # populate contact selectbox with all members of the 1st company found in the query above (number_of = company_members_id of first match found)
            member_ids = selectbox_most_recent_company_members.strip(";").split(";")

            query_selectbox_members = models_contacts.objects.filter(id_contact__in=member_ids)

            selectbox_members = [model_to_dict(l) for l in query_selectbox_members]
            selectbox_members = sorted(selectbox_members, key=lambda x: x['id_contact'] == '0')

            # Get default member by matching pk to populate selectbox
            query_default_selected_member = models_contacts.objects.filter(
                id_contact__icontains=pk
            )

            default_selected_member = [model_to_dict(l) for l in query_default_selected_member]
            default_selected_member_id = str([d['id_contact'] for d in default_selected_member]).replace("[", '').replace("]", '').replace("'", '').replace(";", '')

            if not selectbox_members:
                selectbox_members = default_selected_member

            list_product_denomination = models_products.objects.values_list('product_denomination', flat=True)
            list_product_denomination = list(list_product_denomination)

            list_id_product = models_products.objects.values_list('id_product', flat=True)
            list_id_product = list(list_id_product)

        return render(request, 'update_record.html', {
            'selectbox_company_project': selectbox_company_project,
            'selectbox_all_companies': selectbox_all_companies,
            'selectbox_members': selectbox_members,
            'default_selected_member_id': default_selected_member_id,
            'selectbox_most_recent_company_members_id': selectbox_most_recent_company_members_id,
            'selectbox_most_recent_company_members': selectbox_most_recent_company_members,
            'selectbox_most_recent_company': selectbox_most_recent_company,

        })
    else:
        messages.success(request, "You Must Be Logged In...")
        return redirect('home')

####################################################################################
def update_project_mobile(request):
    if request.user.is_authenticated:

        project_num = request.GET.get('project_num')  # have to pass it also in Ajax

        current_record2 = models_projects.objects.get(id_project=project_num) # id= can be replace by any field on the DB
        projects_form = forms_projects(request.POST or None, instance=current_record2)

        if projects_form.is_valid():
            projects_instance = projects_form.save(commit=False)
            projects_instance.project_denomination = projects_instance.project_denomination[:200]
            projects_instance.save()


        return render(request, 'projects_mobile.html', {'projects_form':projects_form})
    else:
        messages.success(request, "You Must Be Logged In...")
        return redirect('home')

def update_company_mobile(request):
    if request.user.is_authenticated:

        company_num = request.GET.get('company_num')  # have to pass it also in Ajax

        current_record8 = models_companies.objects.get(id_company=company_num) # id= can be replace by any field on the DB
        company_form = forms_companies(request.POST or None, instance=current_record8)

        if company_form.is_valid():
            company_instance = company_form.save(commit=False)
            company_instance.company_name = company_instance.company_name[:200]
            company_instance.save()



        return render(request, 'company_mobile.html', {'company_form':company_form, 'company_num':company_num})
    else:
        messages.success(request, "You Must Be Logged In...")
        return redirect('home')

def update_contact_mobile(request): #pk is due in forms.py inclass forms_contacts
    if request.user.is_authenticated:

        contact_num = request.GET.get('contact_num')  # have to pass it also in Ajax

        current_record2 = models_contacts.objects.get(id_contact=contact_num) # id= can be replace by any field on the DB
        contact_form = forms_contacts(request.POST or None, instance=current_record2, pk=contact_num)


        return render(request, 'contacts_mobile.html', {'contact_form':contact_form, 'contact_num':contact_num})
    else:
        messages.success(request, "You Must Be Logged In...")
        return redirect('home')

def update_interaction(request):

    if request.user.is_authenticated:
        #current_user = request.user.first_name+' '+request.user.last_name
        current_user = request.user.id
        current_contact_id = request.GET.get('current_contact_id')
        current_contact_name = request.GET.get('current_contact_name')
        interaction_id = request.GET.get('interaction_id')  # can maybe be removed and replaced by 0 if always = 0
        current_company_id = request.GET.get('current_company_id')
        current_project_id = request.GET.get('current_project_id')
        current_project_name = request.GET.get('current_project_name')

        new_interaction_request = models_interactions.objects.get(id_interaction=interaction_id)
        new_interaction_form = forms_interactions(request.POST or None, instance=new_interaction_request,initial={"interaction_user":current_user,
                                                                                                                  "interaction_contact_id":current_contact_id,
                                                                                                                  "interaction_contact_name":current_contact_name,
                                                                                                                  "interaction_company_id":current_company_id,
                                                                                                                  "interaction_project_id": current_project_id,
                                                                                                                  "interaction_project_name":current_project_name,
                                                                                                                  })


        return render(request, 'interaction_mobile.html', {'new_interaction_form':new_interaction_form,
                                                           'current_user':current_user,})
    else:
        messages.success(request, "You Must Be Logged In...")
        return redirect('home')
####################################################################################

def update_sales_documents_and_company_addresses(request):
    if not request.user.is_authenticated:
        return JsonResponse({'error': 'Utilisateur non connecté'}, status=403)

    if request.method == "POST":
        id_company = request.POST.get('id_company')
        id_sales_document = request.POST.get('id_sales_document')
        selectbox_id = request.POST.get('selectbox_id')
        id_address = request.POST.get('id_address')

        try:
            if selectbox_id == "selectbox_company_address":
                company = models_companies.objects.get(id_company=id_company)
                company.company_head_quarter_address_id = id_address
                company.save()

            elif selectbox_id == "selectbox_billing_address" and id_sales_document != '0':
                sales_document = models_sales_documents.objects.get(id_sales_documents=id_sales_document)
                sales_document.sales_documents_billing_address_id = id_address
                sales_document.save()

            elif selectbox_id == "selectbox_delivery_address" and id_sales_document != '0':
                sales_document = models_sales_documents.objects.get(id_sales_documents=id_sales_document)
                sales_document.sales_documents_delivery_address_id = id_address
                sales_document.save()

            return JsonResponse({'success': True})
        except Exception as e:
            return JsonResponse({'error': str(e)}, status=500)

    return JsonResponse({'error': 'Méthode non autorisée'}, status=405)

def update_address_mobile(request):
    if request.user.is_authenticated:

        id_address = request.GET.get('id_address')  # have to pass it also in Ajax

        form_address_query = models_addresses.objects.get(id_address=id_address)  # id= can be replace by any field on the DB
        form_address = forms_addresses(request.POST or None, instance=form_address_query)

        if form_address.is_valid():
            address_instance = form_address.save(commit=False)
            address_instance.address_title = address_instance.address_title[:200]
            address_instance.address_type = address_instance.address_type[:200]
            address_instance.save()


        return render(request, 'address_mobile.html', {'form_address': form_address, 'id_address': id_address})
    else:
        messages.success(request, "You Must Be Logged In...")
        return redirect('home')
####################################################################################

def update_sales_documents_edit(request):
    if not request.user.is_authenticated:
        return JsonResponse({"error": "unauthorized"}, status=403)

    sales_documents_id = request.GET.get('selectbox_update_record_sales_documents_edit_id')
    instance = models_sales_documents.objects.get(id_sales_documents=sales_documents_id)

    # 📝 Formulaires
    form_edit = forms_sales_documents_products(request.POST or None, instance=instance)
    form_infos = forms_sales_documents_infos(request.POST or None, instance=instance)
    form_billing = forms_sales_documents_billing(request.POST or None, instance=instance)
    form_delivery = forms_sales_documents_delivery(request.POST or None, instance=instance)
    form_payment = forms_sales_documents_payment_conditions(request.POST or None, instance=instance)

    # 📦 Produits : liste complète + map
    product_list =  [{"id": "", "denomination": "", "category": ""}]+[{"id": "#", "denomination": "Ajouter un nouveau produit", "category": ""}]+[
        {"id": p.id_product, "denomination": p.product_denomination, "category": p.product_category}
        for p in models_products.objects.all()
    ]

    product_id_to_name = {
        p.id_product: p.product_denomination
        for p in models_products.objects.all()
    }

    # 🔄 Valeurs sélectionnées pour l'édition
    selected_denomination_vars = {}
    for i in range(1, 26):
        field_name = f"sales_documents_description_{i}"
        product_id = getattr(instance, field_name, "")
        selected_value = product_id_to_name.get(product_id, "")
        selected_denomination_vars[f"selected_denomination_{i}"] = selected_value

    # 📌 Contexte commun
    base_context = {
        "product_list": product_list,
        "list_product_denomination": list(models_products.objects.values_list('product_denomination', flat=True)),
        "list_id_product": list(models_products.objects.values_list('id_product', flat=True)),
        **selected_denomination_vars
    }

    # 🔍 🟢 Calcul du prochain numéro de paiement (next_number)
    all_numbers_raw = models_sales_documents.objects.values_list('sales_documents_deposit_number', flat=True)
    numbers = []
    for raw in all_numbers_raw:
        if not raw:
            continue
        # Découpe la chaîne en parts valides (évite les ; vides)
        parts = [s.strip() for s in raw.split(';') if s.strip()]
        numbers.extend(parts)

    if not numbers:
        # Aucun paiement → premier numéro
        next_number = 'FA01'
    else:
        # Fonction pour extraire la partie numérique (ex: "FA34:FA44" → "34")
        def extract_number(n):
            n_clean = n.split(':')[0]  # Prend le premier numéro si multiple (séparé par :)
            return int(''.join(filter(str.isdigit, n_clean)) or 0)

        max_num = max([extract_number(n) for n in numbers])
        next_number = f'FA{max_num + 1:02d}'

    # 🔁 Réponse complète avec le next_number ajouté
    return JsonResponse({
        "html_edit": render_to_string('sales_documents_products.html', {
            "context_form_sales_documents_document_edit": form_edit,
            **base_context
        }, request=request),
        "html_infos": render_to_string('sales_documents_infos.html', {
            "form": form_infos
        }, request=request),
        "html_billing": render_to_string('sales_documents_billing.html', {
            "form": form_billing
        }, request=request),
        "html_delivery": render_to_string('sales_documents_delivery.html', {
            "form": form_delivery
        }, request=request),
        "html_payment_conditions": render_to_string('sales_documents_payment_conditions.html', {
            "form": form_payment
        }, request=request),

        "list_product_denomination_json": list(models_products.objects.values_list('id_product', 'product_denomination')),
        "list_id_product_json": list(models_products.objects.values_list('id_product', flat=True)),

        "next_deposit_number": next_number  # ✅ Ajout du prochain numéro pour JS
    })





def create_product_ajax(request):
    if request.method == 'POST':
        # 🔐 Sécurise les champs POST
        line_index = request.POST.get('line_index')  # 📌 Ligne à modifier (1 à 25)
        document_id = request.POST.get('document_id')  # 🆔 ID du document concerné

        # 🛠️ Création du produit dans models_products
        product = models_products.objects.create(
            id_product=(datetime.now() + timedelta(hours=2)).strftime('%Y%m%d%H%M%S%f')[:16],
            product_last_modification_date=(datetime.now() + timedelta(hours=2, seconds=3)).strftime('%Y%m%d%H%M%S%f')[:16],
            product_last_modification_user=request.user.id,
            product_category=request.POST.get('product_category'),
            product_reference=request.POST.get('product_reference'),
            product_denomination=request.POST.get('product_denomination'),
            product_prix_achat=request.POST.get('product_prix_achat'),
            product_prix_vente=request.POST.get('product_prix_vente'),
            product_prix_location=request.POST.get('product_prix_location'),
            product_poids=request.POST.get('product_poids'),
            product_volume=request.POST.get('product_volume'),
            product_dimensions=request.POST.get('product_dimensions'),
            product_consommation={},
            product_quantite_colis={},
            product_sous_traitant={},
        )


        # ✅ Réponse
        return JsonResponse({
            'status': 'success',
            'new_product_id': product.id_product,
            'new_product_denomination': product.product_denomination
        })

    return JsonResponse({'status': 'error', 'message': 'Méthode non autorisée'}, status=405)




def update_sales_documents_last_modification_date(request):
    sales_document_id = request.POST.get('sales_document_id')

    if not sales_document_id:
        return JsonResponse({"error": "ID manquant"}, status=400)

    # 🧪 On vérifie d'abord si l'ID existe vraiment en base
    if not models_sales_documents.objects.filter(id_sales_documents=sales_document_id).exists():
        # 📦 Si le document n'existe pas encore (nouveau), on renvoie juste la date à injecter côté client
        new_date = (datetime.now() + timedelta(hours=2)).strftime('%Y%m%d%H%M%S%f')[:16]
        return JsonResponse({
            "updated_sales_documents_last_modification_date": new_date,
            "status": "not_saved_yet"
        })

    try:
        doc = models_sales_documents.objects.get(id_sales_documents=sales_document_id)
        new_date = (datetime.now() + timedelta(hours=2)).strftime('%Y%m%d%H%M%S%f')[:16]
        doc.sales_documents_last_modification_date = new_date
        doc.save()
        return JsonResponse({
            "updated_sales_documents_last_modification_date": new_date,
            "status": "saved"
        })
    except Exception as e:
        return JsonResponse({"error": str(e)}, status=500)

def update_project_last_modification_date(request):

    project_id = request.POST['project_id']
    current_projects_id = models_projects.objects.get(id_project=project_id)
    current_projects_id.project_last_modification_date = (datetime.now() + timedelta(hours=2)).strftime('%Y%m%d%H%M%S%f')[:16]
    current_projects_id.save()  # this will update only

    updated_project_last_modification_date = models_projects.objects.filter(id_project=project_id).values_list('project_last_modification_date', flat=True)

    return JsonResponse({"updated_project_last_modification_date":updated_project_last_modification_date[0]})
####################################################################################

#Maybe can be donne in only one view for all contact, companies, addresses, project and documents ?
def check_project_last_modification_date(request):
    if request.method != 'POST':
        return JsonResponse({'status': 'error', 'message': 'Requête non valide.'})

    # 📥 Données POST
    project_id = request.POST.get('project_id')
    current_date = request.POST.get('current_date')
    serialized_form = request.POST.get('current_form', '')

    # 🔍 Récupère le projet en base
    try:
        project = models_projects.objects.get(id_project=project_id)
    except models_projects.DoesNotExist:
        return JsonResponse({'status': 'error', 'message': 'Projet non trouvé.'})

    # ✅ Si la date n’a pas changé, pas besoin de comparer le contenu
    if project.project_last_modification_date == current_date:
        return JsonResponse({'status': 'ok'})

    # 👤 Récupération des infos utilisateur ayant modifié le projet
    try:
        user = User.objects.get(id=int(project.project_last_modification_user))
        user_last_name = user.last_name
        user_first_name = user.first_name
    except (User.DoesNotExist, ValueError, TypeError):
        user_last_name = "Inconnu"
        user_first_name = "Inconnu"

    # 🔄 Décodage du formulaire sérialisé reçu (clé = nom du champ, valeur = texte)
    from_form = {k: v[0] for k, v in parse_qs(serialized_form).items()}

    # 🚫 Champs à ignorer dans la comparaison
    ignored_fields = {
        'csrfmiddlewaretoken',
        'project_last_modification_user',
        'project_last_modification_date',
    }

    # ✅ Liste de tous les champs du modèle à vérifier
    all_fields_to_check = [
        field.name for field in models_projects._meta.fields if field.name not in ignored_fields
    ]

    modifications = {}  # Dictionnaire des différences détectées

    # 🔍 Comparaison champ par champ (formulaire vs base)
    for key in all_fields_to_check:
        if not hasattr(project, key):
            continue  # Sécurité

        db_value = getattr(project, key)
        db_value = '' if db_value is None else str(db_value)

        # ⚠️ Si le champ n’est pas dans le form, on suppose qu’il est vide
        client_value = from_form.get(key, '')

        # 🟡 Si la valeur diffère, on l’ajoute aux conflits
        if client_value != db_value:
            modifications[key] = {
                'ancienne': db_value,
                'nouvelle': client_value
            }

    # ✅ Si aucune réelle différence, on évite un conflit inutile
    if not modifications:
        return JsonResponse({
            'status': 'no_conflict',
            'message': 'La date a changé, mais les données n’ont pas été modifiées.',
            'user_last_name': user_last_name,
            'user_first_name': user_first_name
        })

    # ❌ Conflit détecté avec différences → retour complet
    return JsonResponse({
        'status': 'conflict',
        'user_last_name': user_last_name,
        'user_first_name': user_first_name,
        'modifications': modifications
    })

def check_address_last_modification_date(request):
    if request.method == 'POST':
        address_id = request.POST.get('address_id')
        current_date = request.POST.get('current_date')

        try:
            address = models_addresses.objects.get(id_address=address_id)
        except models_addresses.DoesNotExist:
            return JsonResponse({'status': 'error', 'message': 'Adresse non trouvée.'})

        if address.address_last_modification_date != current_date:
            try:
                user_id = int(address.address_last_modification_user)  # conversion explicite
                user = User.objects.get(id=user_id)
                user_last_name = user.last_name
                user_first_name = user.first_name
            except (User.DoesNotExist, ValueError):
                user_last_name = "Inconnu"
                user_first_name = "Inconnu"

            return JsonResponse({
                'status': 'conflict',
                'user_last_name': user_last_name,
                'user_first_name': user_first_name
            })

        return JsonResponse({'status': 'ok'})

    return JsonResponse({'status': 'error', 'message': 'Requête non valide.'})

####################################################################################

def sales_documents_all_forms_save_without_refresh(request):
    # ✅ Vérifie que la requête est bien en POST
    if request.method != "POST":
        return JsonResponse({"result": "method not allowed"}, status=405)

    # 🔎 Récupère les données essentielles du POST
    id_sales_documents = request.POST.get('id_sales_documents')
    new_tag = request.POST.get('new_sales_documents_tag')  # '0' = création, sinon édition
    project_num = request.POST.get('project_num')
    document_type_number_to_be_created = request.POST.get('document_type_number_to_be_created')
    next_timeline_step = request.POST.get('next_timeline_step')

    # 📦 Variables de réponse initiales
    result = "unknown"
    updated_project_sales_documents_list = []
    errors = {}

    # 🔁 Si c’est une création de document
    if new_tag == '0':
        # ➕ Crée un nouvel objet vide (pas encore en DB)
        instance = models_sales_documents(id_sales_documents=id_sales_documents)

        # 🔗 Lier ce document au projet (si pas déjà lié)
        current_links = models_projects.objects.filter(id_project=project_num).values_list('project_sales_document', flat=True).first() or ''
        if f";{id_sales_documents};" not in current_links:
            project_instance = models_projects.objects.get(id_project=project_num)
            project_instance.project_sales_document = current_links + id_sales_documents + ';'
            project_instance.save()

        # 🔒 Pas de valeurs à préserver en création
        old_billing = ''
        old_delivery = ''

    else:
        # 📝 Sinon, c’est une édition d’un document existant
        instance = models_sales_documents.objects.get(id_sales_documents=id_sales_documents)

        # 🔒 Sauvegarde des valeurs d’adresses avant écrasement par les formulaires
        previous = models_sales_documents.objects.get(id_sales_documents=id_sales_documents)
        old_billing = previous.sales_documents_billing_address_id
        old_delivery = previous.sales_documents_delivery_address_id

    # 📝 Création des 5 formulaires liés au même `instance`
    form_main = forms_sales_documents_products(request.POST, instance=instance)
    form_infos = forms_sales_documents_infos(request.POST, instance=instance)
    form_billing = forms_sales_documents_billing(request.POST, instance=instance)
    form_delivery = forms_sales_documents_delivery(request.POST, instance=instance)
    form_payment = forms_sales_documents_payment_conditions(request.POST, instance=instance)

    # ✅ Si TOUS les formulaires sont valides
    if all([form_main.is_valid(), form_infos.is_valid(), form_billing.is_valid(), form_delivery.is_valid(), form_payment.is_valid()]):
        # 💾 Sauvegarde de tous les formulaires
        form_main.save()
        form_infos.save()
        form_billing.save()
        form_delivery.save()
        form_payment.save()

        # 🔁 Recharge l’instance depuis la BDD pour manipulations finales
        doc_instance = models_sales_documents.objects.get(id_sales_documents=id_sales_documents)

        # 🔐 Réinjecte les valeurs sensibles (adresses) qui ne doivent pas être écrasées
        doc_instance.sales_documents_billing_address_id = old_billing
        doc_instance.sales_documents_delivery_address_id = old_delivery
        # 🔐 Sauvegarde l'utilisateur django qui a sauvegardé
        doc_instance.sales_documents_last_modification_user = request.user.id

        # 🟢 Si un numéro doit être généré (quote / delivery_note / invoice)
        if document_type_number_to_be_created in ['quote', 'delivery_note', 'invoice']:
            # 📅 Date du jour au format YYYYMMDD
            today_str = datetime.now().strftime("%Y%m%d")

            # 🟡 Détermine le préfixe et la colonne concernée
            if document_type_number_to_be_created == 'quote':
                column_name = 'sales_documents_quote_number'
                rent_or_sale = doc_instance.sales_documents_rent_or_sale
                if rent_or_sale == 'rent':
                    prefix = 'DL'
                elif rent_or_sale == 'sale':
                    prefix = 'DV'
                else:
                    prefix = 'ERROR'
            elif document_type_number_to_be_created == 'delivery_note':
                prefix = 'BL'
                column_name = 'sales_documents_delivery_note_number'
            elif document_type_number_to_be_created == 'invoice':
                prefix = 'FA'
                column_name = 'sales_documents_invoice_number'

            # 🔍 Recherche des numéros existants du jour
            all_numbers = models_sales_documents.objects.values_list(column_name, flat=True)
            numbers_today = []
            for raw in all_numbers:
                if not raw:
                    continue
                parts = [s.strip() for s in raw.split(';') if s.strip()]
                for part in parts:
                    if part.startswith(f"{prefix}{today_str}"):
                        numbers_today.append(part)

            # 🔢 Calcule le prochain numéro à générer
            if not numbers_today:
                next_number = f"{prefix}{today_str}/V1"
            else:
                max_version = 1
                for n in numbers_today:
                    if '/V' in n:
                        try:
                            version = int(n.split('/V')[1])
                            max_version = max(max_version, version)
                        except:
                            pass
                next_number = f"{prefix}{today_str}/V{max_version + 1}"

            # ✅ Assigne le numéro généré au champ correspondant
            setattr(doc_instance, column_name, next_number)

        # 🔁 Direct: les <select> renvoient déjà l’ID
        for i in range(1, 26):
            field = f'sales_documents_description_{i}'
            product_id = request.POST.get(field, '').strip()
            setattr(doc_instance, field, product_id or "")

        # 🔁 Mise à jour de la liste des sales_documents liés au projet
        updated = models_projects.objects.filter(id_project=project_num).values_list('project_sales_document', flat=True).first()
        updated_project_sales_documents_list = updated if updated else []

        # 🟢 Si le document est à un stade timeline défini, on met à jour la colonne correspondante
        if next_timeline_step in ['quote', 'deposit', 'delivery_note', 'invoice']:
            doc_instance.sales_documents_timeline_step = next_timeline_step

            # ✅ ✅ ✅ AJOUT demandé : si c’est un step important → valider le projet parent
            if next_timeline_step in ['deposit', 'delivery_note', 'invoice']:
                try:
                    project_to_validate = models_projects.objects.get(id_project=project_num)
                    project_to_validate.project_maturity = 'Validated'
                    project_to_validate.project_credibility = 'Validated'
                    project_to_validate.save()
                except models_projects.DoesNotExist:
                    pass  # 🛑 Si le projet n'existe pas, ne plante pas

        # ✅ Sauvegarde finale du document
        doc_instance.save()

        # ✅ Tout est validé
        result = "save success"

    else:
        # ❌ Échec de validation → capture les erreurs des formulaires
        if not form_main.is_valid():
            errors['main'] = form_main.errors
        if not form_infos.is_valid():
            errors['infos'] = form_infos.errors
        if not form_billing.is_valid():
            errors['billing'] = form_billing.errors
        if not form_delivery.is_valid():
            errors['delivery'] = form_delivery.errors
        if not form_payment.is_valid():
            errors['payment'] = form_payment.errors

        result = "save failed"

    # 📤 Réponse JSON avec résultat et erreurs (si présentes)
    return JsonResponse({
        "result": result,
        "errors": errors,
        "updated_project_sales_documents_list": updated_project_sales_documents_list
    })

def update_toggle_sales_documents_save_without_refresh(request):
    try:
        id_sales_document = request.POST.get("id_sales_document")
        value = request.POST.get("sales_documents_rent_or_sale")

        if not id_sales_document or not value:
            return JsonResponse({"error": "ID ou valeur manquante."}, status=400)

        # Récupère le document concerné
        sales_document = models_sales_documents.objects.get(id_sales_documents=id_sales_document)

        # Met à jour la colonne avec la nouvelle valeur
        sales_document.sales_documents_rent_or_sale = value
        sales_document.save()

        return JsonResponse({"message": "Mise à jour réussie."}, status=200)

    except models_sales_documents.DoesNotExist:
        return JsonResponse({"error": "Document introuvable."}, status=404)
    except Exception as e:
        return JsonResponse({"error": str(e)}, status=500)

def duplicate_sales_document(request):
    if request.method != "POST":
        return JsonResponse({"result": "method not allowed"}, status=405)

    source_doc_id = request.POST.get('source_doc_id')
    target_project_id = request.POST.get('target_project_id')

    try:
        source_doc = models_sales_documents.objects.get(id_sales_documents=source_doc_id)
        project = models_projects.objects.get(id_project=target_project_id)
    except models_sales_documents.DoesNotExist:
        return JsonResponse({"result": "error", "error": "Document source introuvable"})
    except models_projects.DoesNotExist:
        return JsonResponse({"result": "error", "error": "Projet cible introuvable"})

    # 🆕 Génère un nouvel ID à 16 chiffres
    now = datetime.now()
    new_id = (datetime.now() + timedelta(hours=2)).strftime('%Y%m%d%H%M%S%f')[:16]
    new_modif_date = (datetime.now() + timedelta(hours=2, milliseconds=22)).strftime('%Y%m%d%H%M%S%f')[:16]


    # 💾 Clone du document
    doc_copy = copy.copy(source_doc)
    doc_copy.pk = None  # Pour créer un nouveau record
    doc_copy.id_sales_documents = new_id
    doc_copy.sales_documents_denomination = f"{source_doc.sales_documents_denomination}_duplicated"
    doc_copy.sales_documents_timeline_step = "quote"
    doc_copy.sales_documents_last_modification_date = new_modif_date
    doc_copy.sales_documents_last_modification_user = request.user.id

    # 🧹 Nettoyage des champs spécifiques
    for field in [
        'sales_documents_quote_id',
        'sales_documents_quote_number',

        'sales_documents_purchase_order_id',
        'sales_documents_purchase_order_number',

        'sales_documents_delivery_note_id',
        'sales_documents_delivery_note_number',

        'sales_documents_invoice_id',
        'sales_documents_invoice_number',

        'sales_documents_deposit_id',
        'sales_documents_deposit_number',
        'sales_documents_deposit_date',
        'sales_documents_deposit_amount',

        'sales_documents_ref_contact_id'
    ]:
        setattr(doc_copy, field, '')

    doc_copy.save()

    # 🔗 Ajout du document à la liste du projet
    old_list = project.project_sales_document or ''
    if f";{new_id};" not in old_list:
        project.project_sales_document = old_list + new_id + ';'
        project.save()

    return JsonResponse({"result": "success", "new_doc_id": new_id})

def update_contact_mobile_save_without_refresh(request):
    #contact_num = request.POST['id_contact']
    #contact_num = pk

    contact_id = request.POST['id_contact']
    create_new_contact_from_serialized_data = request.POST['selectbox_current_company']
    new_contact_tag = request.POST['new_contact_tag']

    if new_contact_tag == '0':

        current_company_members_id_value = models_companies.objects.filter(id_company=create_new_contact_from_serialized_data).values_list('company_members_id', flat=True)

        if ';' + contact_id + ';' not in current_company_members_id_value[0]:

            current_company_members_id = models_companies.objects.get(id_company=create_new_contact_from_serialized_data)
            current_company_members_id.company_members_id = current_company_members_id_value[0] + contact_id + ';'  # change field
            current_company_members_id.save()  # this will update only

            result_2 = 'OK'
        else:
            result_2 = 'existe deja'

        # instance_create_new_contact = models_contacts.objects.get(id_contact=create_new_contact_from_serialized_data)  # 20240828183412
        contact_form = forms_contacts(request.POST or None, pk=contact_id)

        if request.method == "POST":
            if contact_form.is_valid():
                contact_instance = contact_form.save(commit=False)
                contact_instance.contact_first_name = contact_instance.contact_first_name[:100]
                contact_instance.contact_last_name = contact_instance.contact_last_name[:100]
                contact_instance.save()
                result = 'save success'
            else:
                result = 'save failed'
            return JsonResponse({"result": result, "result_2":result_2})
        else:
            return render(request, 'contacts_mobile.html', context={"result": 0})
    else:

        current_record2 = models_contacts.objects.get(id_contact=contact_id)  # id= can be replace by any field on the DB
        contact_form = forms_contacts(request.POST or None, instance=current_record2, pk=contact_id)

        if request.method == "POST":
            if contact_form.is_valid():
                contact_instance = contact_form.save(commit=False)
                contact_instance.contact_first_name = contact_instance.contact_first_name[:100]
                contact_instance.contact_last_name = contact_instance.contact_last_name[:100]
                contact_instance.save()
                result = 'save success'
                result_2 = 'OK saved existing'
            else :
                result = 'save failed'
                result_2 = 'save failed existing'
            return JsonResponse({"result": result,  "result_2":result_2})
        else:
            return render(request, 'contacts_mobile.html', context={"result": 0})

def update_company_mobile_save_without_refresh(request):

    company_id = request.POST['id_company']
    current_contact_id = request.POST['selectbox_current_contact']
    new_company_tag = request.POST['new_company_tag']

    if new_company_tag == '0':

        company_form = forms_companies(request.POST or None)

        if request.method == "POST":
            if company_form.is_valid():
                company_instance = company_form.save(commit=False)
                company_instance.company_name = company_instance.company_name[:200]
                company_instance.save()
                result = 'save success'
            else:
                result = 'save failed'
            return JsonResponse({"result": result})
        else:
            return render(request, 'company_mobile.html', context={"result": 0})
    else:

        current_record2 = models_companies.objects.get(id_company=company_id)  # id= can be replace by any field on the DB
        company_form = forms_companies(request.POST or None, instance=current_record2)

        if request.method == "POST":
            if company_form.is_valid():
                company_instance = company_form.save(commit=False)
                company_instance.company_name = company_instance.company_name[:200]
                company_instance.save()
                result = 'save success'

            else :
                result = 'save failed '+company_id

            return JsonResponse({"result": result})
        else:
            return render(request, 'company_mobile.html', context={"result": 0})

def update_project_mobile_save_without_refresh(request):
    if request.method != "POST":
        return JsonResponse({"error": "Invalid request method"}, status=405)

    # Sécurité : récupération des données POST avec .get()
    project_id = request.POST.get('id_project')
    company_id = request.POST.get('selectbox_current_company')
    new_project_tag = request.POST.get('new_project_tag')

    if not project_id or not company_id or new_project_tag is None:
        return JsonResponse({"error": "Missing required POST data"}, status=400)

    # initialise variables
    result = "save failed"
    result_2 = "unknown"

    if new_project_tag == '0':
        # Création d'un nouveau projet
        company = models_companies.objects.filter(id_company=company_id).first()
        if not company:
            return JsonResponse({"error": "Company not found"}, status=404)

        existing_projects = company.company_projects_id or ""

        if f";{project_id};" not in existing_projects:
            company.company_projects_id = existing_projects + project_id + ';'
            company.save()
            result_2 = "OK"
        else:
            result_2 = "existe deja"

        project_form = forms_projects(request.POST or None)
        if project_form.is_valid():
            project_instance = project_form.save(commit=False)

            new_sales_documents_id = (datetime.now() + timedelta(hours=2)).strftime('%Y%m%d%H%M%S%f')[:16]
            new_sales_documents_last_modification_date = (datetime.now() + timedelta(hours=2, seconds=5)).strftime('%Y%m%d%H%M%S%f')[:16]
            new_sales_documents_quote_id = (datetime.now() + timedelta(hours=2, seconds=9)).strftime('%Y%m%d%H%M%S%f')[:16]

            new_sales_documents = models_sales_documents.objects.create(
                id_sales_documents=new_sales_documents_id,
                sales_documents_denomination=(project_instance.project_denomination+' V1')[:200],
                sales_documents_last_modification_date=new_sales_documents_last_modification_date,
                sales_documents_quote_id=new_sales_documents_quote_id,
            )
            project_instance.project_denomination = project_instance.project_denomination[:200]
            project_instance.project_sales_document = f";0;{new_sales_documents_id};"
            project_instance.save()

            result = "save success"
        else:
            result = f"save failed: {project_form.errors.as_json()}"

        return JsonResponse({"result": result, "result_2": result_2})

    else:
        # Mise à jour d’un projet existant
        try:
            current_project = models_projects.objects.get(id_project=project_id)
        except models_projects.DoesNotExist:
            return JsonResponse({"error": "Project not found"}, status=404)

        project_form = forms_projects(request.POST or None, instance=current_project)

        if project_form.is_valid():
            project_instance = project_form.save(commit=False)
            project_instance.project_denomination = project_instance.project_denomination[:200]
            project_instance.save()

            result = "save success"
            result_2 = "OK saved existing"
        else:
            result = "save failed"
            result_2 = "save failed existing"

        return JsonResponse({"result": result, "result_2": result_2})

def update_interaction_save_without_refresh(request):

    new_interaction_form = forms_interactions(request.POST or None)

    if request.method == "POST":
        if new_interaction_form.is_valid():
            new_interaction_instance = new_interaction_form.save(commit=False)
            new_interaction_instance.interaction_content = new_interaction_instance.interaction_content[:59000]
            new_interaction_instance.save()

            result = 'save success'
        else:
            result = 'save failed'
        return JsonResponse({"result": result})
    else:
        return render(request, 'interaction_mobile.html', context={"result": 0})

def update_address_mobile_save_without_refresh(request):
    if request.method != "POST":
        return JsonResponse({"result": "invalid request"})

    address_id = request.POST.get('id_address')
    company_num = request.POST.get('company_num')
    id_sales_document = request.POST.get('id_sales_document')
    div_container_if_new_address =request.POST.get('div_container_if_new_address')

    if not address_id:
        return JsonResponse({"result": "missing address_id"})

    address_exists = models_addresses.objects.filter(id_address=address_id).exists()

    if address_exists:
        address_instance = models_addresses.objects.get(id_address=address_id)
        address_form = forms_addresses(request.POST, instance=address_instance)
    else:
        address_form = forms_addresses(request.POST)

    if address_form.is_valid():
        # Si nouvelle adresse : forcer l'ID
        if not address_exists:
            address_form.instance.id_address = address_id

        address_form.save()

        # Mise à jour de company_addresses_id uniquement si nouvelle adresse
        if not address_exists:
            try:
                company = models_companies.objects.get(id_company=company_num)
                current_value = company.company_addresses_id or ';'  # Si None, on initialise à ";"

                if f';{address_id};' not in current_value:
                    company.company_addresses_id = current_value + address_id + ';'
                    company.save()
            except models_companies.DoesNotExist:
                return JsonResponse({"result": "company not found"})

        # if adresse is new, 'div_container_if_new_address' returns the id of the parent div of the form to know if its company, billing or delivery to update with new id_address for selectbox to have created address as selected otion
        if div_container_if_new_address:
            if div_container_if_new_address == 'div_form_update_record_company_address_container':
                company = models_companies.objects.get(id_company=company_num)
                company.company_head_quarter_address_id = address_id
                company.save()
            if not id_sales_document == '0':
                if div_container_if_new_address == 'div_form_update_record_billing_address_container':
                    sales_document = models_sales_documents.objects.get(id_sales_documents=id_sales_document)
                    sales_document.sales_documents_billing_address_id = address_id
                    sales_document.save()
                if div_container_if_new_address == 'div_form_update_record_delivery_address_container':
                    sales_document = models_sales_documents.objects.get(id_sales_documents=id_sales_document)
                    sales_document.sales_documents_delivery_address_id = address_id
                    sales_document.save()

        return JsonResponse({"result": "save success"})
    else:
        return JsonResponse({"result": "save failed"})

####################################################################################

def update_selectbox_contact_mobile(request):
    if not request.user.is_authenticated:
        messages.success(request, "You Must Be Logged In...")
        return redirect('home')

    contact_num = request.GET.get('contact_num')
    company_num = request.GET.get('company_num')
    contact_num_format = f";{contact_num};"

    # Cherche les entreprises où le contact est membre
    companies_with_contact = models_companies.objects.filter(
        company_members_id__icontains=contact_num_format
    )
    selectbox_all_companies = [model_to_dict(company) for company in companies_with_contact]

    # Récupère l'entreprise sélectionnée
    most_recent_company = models_companies.objects.filter(id_company=company_num).first()
    selectbox_most_recent_company = [model_to_dict(most_recent_company)] if most_recent_company else []

    # Récupère les ID de membres de cette entreprise
    members_raw_string = most_recent_company.company_members_id if most_recent_company else ''
    member_ids = [id_ for id_ in members_raw_string.strip(";").split(";") if id_]

    # Récupère les contacts de cette entreprise ou juste le contact si entreprise == '0'
    if company_num == '0':
        members_queryset = models_contacts.objects.filter(id_contact=contact_num)
    else:
        members_queryset = models_contacts.objects.filter(id_contact__in=member_ids)

    selectbox_members = sorted(
        [model_to_dict(contact) for contact in members_queryset],
        key=lambda x: x['id_contact'] == '0'
    )

    # Récupère le membre par défaut (celui sélectionné initialement)
    default_selected = models_contacts.objects.filter(id_contact=contact_num).first()
    default_selected_member_id = str(default_selected.id_contact) if default_selected else ''

    return render(request, 'selectbox_contact_mobile.html', {
        'selectbox_members': selectbox_members,
        'default_selected_member_id': default_selected_member_id,
    })

def update_selectbox_company_mobile(request):
    if not request.user.is_authenticated:
        messages.success(request, "You Must Be Logged In...")
        return redirect('home')

    contact_num = request.GET.get('contact_num')
    company_num = request.GET.get('company_num')
    contact_num_format = f";{contact_num};"

    # Récupère toutes les entreprises où ce contact est membre (ou juste l'entreprise par défaut si contact_num == 0)
    if contact_num == '0':
        companies_queryset = models_companies.objects.filter(id_company=company_num)
    else:
        companies_queryset = models_companies.objects.filter(
            Q(company_members_id__icontains=contact_num_format) | Q(id_company='0')
        )

    selectbox_all_companies = [model_to_dict(company) for company in companies_queryset]
    selectbox_all_companies = sorted(selectbox_all_companies, key=lambda x: x['id_company'] == '0')

    # Extraction propre des IDs de projets
    all_project_ids = []
    for company in selectbox_all_companies:
        raw_ids = company.get('company_projects_id', '')
        all_project_ids.extend([id_ for id_ in raw_ids.strip(';').split(';') if id_])

    company_projects_ids_of_all_companies_where_pk_is_found = ';'.join(all_project_ids)

    # Récupère l'entreprise sélectionnée
    selected_company = models_companies.objects.filter(id_company=company_num).first()
    selectbox_most_recent_company = [model_to_dict(selected_company)] if selected_company else []
    selectbox_most_recent_company_members_id = selected_company.id_company if selected_company else ''

    return render(request, 'selectbox_company_mobile.html', {
        'selectbox_all_companies': selectbox_all_companies,
        'company_projects_ids_of_all_companies_where_pk_is_found': company_projects_ids_of_all_companies_where_pk_is_found,
        'company_num': company_num,
        'selectbox_most_recent_company_members_id': selectbox_most_recent_company_members_id,
    })

def update_selectbox_project_mobile(request):
    if not request.user.is_authenticated:
        messages.success(request, "You Must Be Logged In...")
        return redirect('home')

    company_num = request.GET.get('company_num')

    # Récupérer l'entreprise sélectionnée
    selected_company = models_companies.objects.filter(id_company=company_num).first()
    selectbox_most_recent_company = [model_to_dict(selected_company)] if selected_company else []

    # Extraire et nettoyer les IDs de projets
    company_projects_ids = []
    if selected_company and selected_company.company_projects_id:
        company_projects_ids = [pid for pid in selected_company.company_projects_id.strip(';').split(';') if pid]

    # Récupérer les projets correspondants, triés par dernière modification
    projects_queryset = models_projects.objects.filter(id_project__in=company_projects_ids).order_by('-project_last_modification_date')
    selectbox_company_project = [model_to_dict(project) for project in projects_queryset]

    if not selectbox_company_project:
        selectbox_company_project = [{
            'id_project': '0',
            'project_last_modification_date': '0',
            'project_denomination': 'To add a project please save new company first !'
        }]

    return render(request, 'selectbox_projects_mobile.html', {
        'selectbox_company_project': selectbox_company_project,
    })

def update_selectbox_address_mobile(request):
    # 1. Récupérer le numéro de la société depuis les paramètres GET de la requête
    company_num = request.GET.get('company_num')
    id_sales_document = request.GET.get('id_sales_document')

    # 2. Chercher la société correspondante dans la base de données
    company = models_companies.objects.filter(id_company=company_num).first()

    # 3. Vérifier que la société existe et qu'elle a des adresses associées
    if company and company.company_addresses_id:
        # 4. Nettoyer la chaîne pour enlever les ';' de début et de fin
        address_ids_raw = company.company_addresses_id.strip(';')
        # 5. Séparer la chaîne en une liste d'ID individuels (en retirant les vides éventuels)
        address_ids_list = [id.strip() for id in address_ids_raw.split(';') if id.strip()]
    else:
        # 6. Si pas d'adresse, créer une liste vide
        address_ids_list = []

    # 7. Rechercher toutes les adresses correspondant aux IDs extraits
    addresses_queryset = models_addresses.objects.filter(id_address__in=address_ids_list)

    # 8. Initialiser un dictionnaire vide pour regrouper les adresses par type
    grouped_addresses = {}

    # 9. Parcourir toutes les adresses trouvées
    for address in addresses_queryset:
        # 10. Récupérer le type d'adresse, ou mettre "Autre" si vide
        address_type = address.address_type if address.address_type else "Autre"

        # 11. S'assurer qu'il existe une liste pour ce type dans le dictionnaire
        if address_type not in grouped_addresses:
            grouped_addresses[address_type] = []

        # 12. Ajouter l'adresse sous forme de dictionnaire {valeur: ID, projet: titre} dans la bonne catégorie
        grouped_addresses[address_type].append({
            'address_id': address.id_address,
            'address_title': address.address_title,
            'address_street_name_1': address.address_street_name_1,
            'address_postal_code': address.address_postal_code,
            'address_city': address.address_city,
        })

    # 13. Transformer grouped_addresses en dict standard pour JsonResponse
    all_company_addresses = dict(grouped_addresses)

    current_company_address = models_companies.objects.filter(id_company=company_num).values_list('company_head_quarter_address_id', flat=True).first()
    current_billing_address = models_sales_documents.objects.filter(id_sales_documents=id_sales_document).values_list('sales_documents_billing_address_id', flat=True).first()
    current_delivery_address = models_sales_documents.objects.filter(id_sales_documents=id_sales_document).values_list('sales_documents_delivery_address_id', flat=True).first()

    # 14. Retourner les données au format JSON pour la réponse AJAX
    return JsonResponse({
        'all_company_addresses': all_company_addresses,
        'current_company_address' : current_company_address,
        'current_billing_address' : current_billing_address,
        'current_delivery_address' : current_delivery_address,
    })

def get_sales_documents_ref_contact(request):
    id_sales_document = request.GET.get("id_sales_document")

    try:
        document = models_sales_documents.objects.get(id_sales_documents=id_sales_document)
        return JsonResponse({
            "sales_documents_ref_contact_id": document.sales_documents_ref_contact_id or ""
        })
    except models_sales_documents.DoesNotExist:
        return JsonResponse({"sales_documents_ref_contact_id": ""})

def save_sales_documents_ref_contact(request):
    if request.method == "POST":
        id_sales_document = request.POST.get("id_sales_document")
        contact_id = request.POST.get("contact_id")

        try:
            doc = models_sales_documents.objects.get(id_sales_documents=id_sales_document)
            doc.sales_documents_ref_contact_id = contact_id
            doc.save()
            return JsonResponse({"success": True})
        except models_sales_documents.DoesNotExist:
            return JsonResponse({"success": False, "error": "Document non trouvé"}, status=404)

    return JsonResponse({"success": False, "error": "Requête invalide"}, status=400)

####################################################################################

def test(request):
    return render(request, 'test.html')

def grid(request):
    return render(request, 'grid.html')

def get_sales_documents_product_price(request):
    if request.user.is_authenticated:
        product_id = request.GET.get('product_id')

        product_info = models_products.objects.filter(id_product=product_id).values(
            'product_prix_vente',
            'product_vat'
        ).first()

        if product_info:
            return JsonResponse({
                'success': True,
                'product_prix_vente': product_info['product_prix_vente'],
                'product_vat': product_info['product_vat']
            })
        else:
            return JsonResponse({'success': False, 'error': 'Produit non trouvé'})
    else:
        return JsonResponse({'success': False, 'error': 'Utilisateur non authentifié'})


####################################################################################
#Interaction
def update_contact_interaction(request): #pk is due in forms.py inclass forms_contacts
    if request.user.is_authenticated:

        contact_num = request.GET.get('contact_num')  # have to pass it also in Ajax

        #query_interaction_form = models_interactions.objects.raw("SELECT * FROM table_interactions WHERE '" + contact_num + "' LIKE interaction_contact_id ORDER by interaction_full_date DESC ")  # used to be selectbox_companies_default
        all_contact_interactions_query = models_interactions.objects.filter(interaction_contact_id=contact_num).order_by('-interaction_full_date')
        all_contact_interactions_with_id_replaced_by_name = []
        # Get current django user' name for every interecations of contact_num based on django user's id recorded in table_interaction as his id
        for interaction in all_contact_interactions_query:
            interaction_dict = model_to_dict(interaction)

            try:
                # get user name by query auth_user table
                user = User.objects.get(id=interaction.interaction_user)
                user_full_name = f"{user.first_name} {user.last_name}"
            except User.DoesNotExist:
                user_full_name = "Unknown user - error"

            try:
                contact = models_contacts.objects.get(id_contact=interaction.interaction_contact_id)
                contact_full_name = f"{contact.contact_first_name} {contact.contact_last_name}"
            except models_contacts.DoesNotExist:
                contact_full_name = "Unknown contact - error"

            # teste si le champ est vide ou non avant le get
            if interaction.interaction_project_id:
                try:
                    project = models_projects.objects.get(id_project=interaction.interaction_project_id)
                    project_full_name = f"{project.project_denomination}"
                except models_projects.DoesNotExist:
                    project_full_name = "error project"
            else:
                project_full_name = ""

            # Remplacer dans le dict
            interaction_dict['interaction_user'] = user_full_name
            interaction_dict['interaction_contact_id'] = contact_full_name
            interaction_dict['interaction_project_id'] = project_full_name

            all_contact_interactions_with_id_replaced_by_name.append(interaction_dict)

        return render(request, 'contact_interaction.html', {'all_contact_interactions_with_id_replaced_by_name':all_contact_interactions_with_id_replaced_by_name})
    else:
        messages.success(request, "You Must Be Logged In...")
        return redirect('home')

def update_company_interaction(request): #pk is due in forms.py inclass forms_contacts
    if request.user.is_authenticated:

        company_num = request.GET.get('company_num')  # have to pass it also in Ajax
        company_num = ';'+company_num+';'

        # query_interaction_form = models_interactions.objects.raw("SELECT * FROM table_interactions WHERE '" + contact_num + "' LIKE interaction_contact_id ORDER by interaction_full_date DESC ")  # used to be selectbox_companies_default
        all_company_interactions_query = models_interactions.objects.filter(interaction_company_id__icontains=company_num).order_by('-interaction_full_date')
        all_company_interactions_with_id_replaced_by_name = []
        # Get current django user' name for every interecations of contact_num based on django user's id recorded in table_interaction as his id
        for interaction in all_company_interactions_query:
            interaction_dict = model_to_dict(interaction)

            try:
                # get user name by query auth_user table
                user = User.objects.get(id=interaction.interaction_user)
                user_full_name = f"{user.first_name} {user.last_name}"
            except User.DoesNotExist:
                user_full_name = "Unknown user - error"

            try:
                contact = models_contacts.objects.get(id_contact=interaction.interaction_contact_id)
                contact_full_name = f"{contact.contact_first_name} {contact.contact_last_name}"
            except models_contacts.DoesNotExist:
                contact_full_name = "Unknown contact - error"

            # teste si le champ est vide ou non avant le get
            if interaction.interaction_project_id:
                try:
                    project = models_projects.objects.get(id_project=interaction.interaction_project_id)
                    project_full_name = f"{project.project_denomination}"
                except models_projects.DoesNotExist:
                    project_full_name = "error project"
            else:
                project_full_name = ""

            # Remplacer dans le dict
            interaction_dict['interaction_user'] = user_full_name
            interaction_dict['interaction_contact_id'] = contact_full_name
            interaction_dict['interaction_project_id'] = project_full_name

            all_company_interactions_with_id_replaced_by_name.append(interaction_dict)

        return render(request, 'company_interaction.html', {'all_company_interactions_with_id_replaced_by_name':all_company_interactions_with_id_replaced_by_name})
    else:
        messages.success(request, "You Must Be Logged In...")
        return redirect('home')

def update_project_interaction(request): #pk is due in forms.py inclass forms_contacts
    if request.user.is_authenticated:

        project_num = request.GET.get('project_num')  # have to pass it also in Ajax

        # query_interaction_form = models_interactions.objects.raw("SELECT * FROM table_interactions WHERE '" + contact_num + "' LIKE interaction_contact_id ORDER by interaction_full_date DESC ")  # used to be selectbox_companies_default
        all_project_interactions_query = models_interactions.objects.filter(interaction_project_id=project_num).order_by('-interaction_full_date')
        all_project_interactions_with_id_replaced_by_name = []
        # Get current django user' name for every interecations of contact_num based on django user's id recorded in table_interaction as his id
        for interaction in all_project_interactions_query:
            interaction_dict = model_to_dict(interaction)

            try:
                # get user name by query auth_user table
                user = User.objects.get(id=interaction.interaction_user)
                user_full_name = f"{user.first_name} {user.last_name}"
            except User.DoesNotExist:
                user_full_name = "Unknown user - error"

            try:
                contact = models_contacts.objects.get(id_contact=interaction.interaction_contact_id)
                contact_full_name = f"{contact.contact_first_name} {contact.contact_last_name}"
            except models_contacts.DoesNotExist:
                contact_full_name = "Unknown contact - error"

            # teste si le champ est vide ou non avant le get
            if interaction.interaction_project_id:
                try:
                    project = models_projects.objects.get(id_project=interaction.interaction_project_id)
                    project_full_name = f"{project.project_denomination}"
                except models_projects.DoesNotExist:
                    project_full_name = "error project"
            else:
                project_full_name = ""

            # Remplacer dans le dict
            interaction_dict['interaction_user'] = user_full_name
            interaction_dict['interaction_contact_id'] = contact_full_name
            interaction_dict['interaction_project_id'] = project_full_name

            all_project_interactions_with_id_replaced_by_name.append(interaction_dict)


        return render(request, 'project_interaction.html', {'all_project_interactions_with_id_replaced_by_name':all_project_interactions_with_id_replaced_by_name})
    else:
        messages.success(request, "You Must Be Logged In...")
        return redirect('home')

def update_selectbox_interaction_project(request):

    # fonction optimisé grace a chatGPT pour return un Json object pour alimenter selectbox avec optgroup

    contact_id = request.GET.get('contact_id')
    if not contact_id:
        return JsonResponse({'grouped_projects': {}})

    # 🔹 Étape 1 : Récupération des entreprises liées au contact
    companies = models_companies.objects.filter(company_members_id__contains=f';{contact_id};')
    companies = [c for c in companies if str(c.id_company) != '0']

    # 🔹 Étape 2 : Extraction de tous les IDs projets liés à ces entreprises
    project_ids = []
    for company in companies:
        raw_ids = company.company_projects_id or ""
        project_ids += [pid for pid in raw_ids.split(';') if pid]

    # 🔹 Étape 3 : Récupération des projets
    projects = models_projects.objects.filter(id_project__in=project_ids).exclude(id_project='0')

    # 🔹 Étape 4 : Groupement des projets par nom d'entreprise
    list_selectbox_interaction_project_grouped_json_formated = {}

    for project in projects:
        project_id = str(project.id_project)
        project_denomination = project.project_denomination

        # Retrouver les entreprises qui contiennent ce projet
        related_companies = models_companies.objects.filter(company_projects_id__contains=f';{project_id};')
        for company in related_companies:
            if str(company.id_company) == '0':
                continue
            company_name = company.company_name

            list_selectbox_interaction_project_grouped_json_formated.setdefault(company_name, []).append({
                'valeur': project_id,
                'projet': project_denomination
            })

    return JsonResponse({'list_selectbox_interaction_project_grouped_json_formated': list_selectbox_interaction_project_grouped_json_formated})


