from datetime import datetime, date,  timedelta, timezone
import datetime as dt
from django.contrib.auth import authenticate, login
from django.contrib.auth.decorators import login_required
import json
from django.http import JsonResponse
from django.shortcuts import redirect, render, HttpResponse

from django.views import View
from .forms import ProduitForm,ArticleFilterForm
from django.contrib import messages
import xmlrpc.client
from django.db.models import Sum
from collections import defaultdict
from .models import *
import time
import copy







product_couvetutre = []
product_couvetutre_dic = {}
Stock_min = []
Stock_min_dic = {}
categories = []
categories_dic = {}
Articles_PF = []
Articles_PF_dic = {}
Articles_MP = []
Articles_MP_dic = {}
Articles_MP_dic_imp = {}
Boms = []
Boms_dic = {}
Bom_Lines = []
Bom_Lines_dic = {}
# Define the object you want to interact with





selected_id =[]
selected_id_dic = {}
# Create your views here.
result_prd = []
result_prd_dic = {}
result_prd_dic = {}
pdp_items=[]
pdp_items_dic = {}

pdp_simulet_items_dic = {}
stock_min_erp = []
stock_min_erp_dic = {}

lot_prd = []
lot_prd_dic = {}
prodcuts_semulatePF = []
prodcuts_semulatePF_dic = {}
prodcuts_pdp_semulateMP = []
prodcuts_pdp_semulateMP_dic = {}
username_erp =''



code_bom=""
name_prd=""
name_bom=""
can_prd = 0
should_prd = 0

prd_pdp_detail_list_dic = {}
result = []  
result_dic = {}
result_dic_sales = {}
selected_id_cbn = []



PF_SM_dic = {}



# Catégorie PF
# Categorie IMP
# Produit fini
# Stock min
# Nomenclatures
# Lignes nomenclatures
# Matiére oremiére
# Produit fini stock min
# PDP list
pdp_list_dic_global = {}
pdp_list_dic = []

plan_appro = []

plan_appro_global = {}

result_dic_Productions = {}

Dic_company_location = {1:420,3:1596,5:1894}


def login_view(request):
    #if request.user.is_authenticated:
        #return redirect('produits:index')
    
    
    if request.method == 'POST':
       
        username = request.POST['username']
        password = request.POST['password']
        
        user = authenticate(request, username=username, password=password)
        
        if user is not None:
            
            login(request, user)  # Connecter l'utilisateur
            request.session['pw'] = password
            
            par = get_paramettre(request.user.username)
            
            print(par.database)
            common = xmlrpc.client.ServerProxy(f'{par.link_db}/xmlrpc/2/common')
            models = xmlrpc.client.ServerProxy(f'{par.link_db}/xmlrpc/2/object')
            uid = common.authenticate(par.database, request.user.username, request.session.get('pw', ''), {})
            
            #print(uid)
            # save categorie pf in session
            request.session['cat_pf'] = par.cat_parent_pf
            # save categorie IMP in session
            request.session['cat_imp'] = par.cat_imporation
            print('cat imp',request.session['cat_imp'])
            # save uid in session
            request.session['uid'] = uid
            request.session['BOM'] = par.Bom
            request.session['Sale_ok'] = par.Sale_ok
            request.session['marque'] = par.marque

            
            #print(request.session.get('pw', ''),request.session.get('cat_pf', ''),request.session.get('cat_imp', ''),request.session.get('uid', ''))

           # [['date', 'month', 0], ['location_dest_id', '=', 9]]
           # ['|', '|', ['location_dest_id', '=', 420], ['location_dest_id', '=', 1894], ['location_dest_id', '=', 1596], ['date', 'month', 0], ['location_id', '!=', 9], ['location_id', '=', 10]]
            champs_CAT = ['id','name','parent_id']
            context1 = {'lang': 'en_US'}
            dom_cat = [('name', 'ilike', request.session.get('cat_imp', ''))]


            global categories,categories_dic
            categories = models.execute_kw(par.database,
                                           request.session.get('uid', ''), 
                                           request.session.get('pw', ''),
                                           'product.category',
                                           'search_read',
                                           [dom_cat],
                                           {'fields': champs_CAT, 'context': context1})
            
            # save categorie imp id  in session
            request.session['cat_imp_id'] = categories[0]['id']

            #categories_dic[request.user.username]=categories
            #print(categories[0]['id'])

            user = models.execute_kw(par.database, 
                                     request.session.get('uid', ''), 
                                     request.session.get('pw', ''),
                                     'res.users',
                                     'read',
                                     [uid], 
                                     {'fields': ['company_id','name']})
            
            
            #print(user['company_id'][0])
            # save id current company  in session
            request.session['current_company_id'] = user['company_id'][0]
            print(request.session['current_company_id'])

            company = get_company_byid(int(request.session['current_company_id']))
            #**************** Get list of final product ******************

            # filtre 
            if request.session['BOM']== True:
                if request.session['Sale_ok']== True:
            
                    dom_PF = [('categ_id.parent_id.name', 'ilike',request.session.get('cat_pf', '')),('sale_ok', '=', True),('active', '=', True),('bom_ids.id', '!=', False)]
                else:
                    dom_PF = [('categ_id.parent_id.name', 'ilike',request.session.get('cat_pf', '')),('sale_ok', '=', False),('purchase_ok', '=', False),('active', '=', True),('bom_ids.id', '!=', False)]
            else:
                if request.session['Sale_ok']== True:
                    dom_PF = [('categ_id.parent_id.name', 'ilike',request.session.get('cat_pf', '')),('sale_ok', '=', True),('active', '=', True)]
                else:
                    dom_PF = [('categ_id.parent_id.name', 'ilike',request.session.get('cat_pf', '')),('sale_ok', '=', False),('purchase_ok', '=', False),('active', '=', True)]



            # les champs a affichés
            champs_PF = ['id','default_code','name','qty_available','virtual_available']
            global Articles_PF_dic
            Articles_PF = models.execute_kw(
                par.database,
                request.session.get('uid', ''), 
                request.session.get('pw', ''),
                'product.product',
                'search_read',  # Odoo model name and method
                [dom_PF],  # Domain for filtering the records (empty list fetches all)
                {
                    'fields': champs_PF,  # Champs à récupérer
                    'context': {'lang': 'fr_FR','location':company.Sales_location}
                }  # Fields you want to retrieve
            )
            #print(Articles_PF)
            Articles_PF_dic[request.user.username]=Articles_PF
            
            Liste_PF_ids = [i['id'] for i in Articles_PF_dic[request.user.username]]
            #print(Liste_PF_ids)

            # ********************* Sales **********************************

            # [['date', 'month', 0], ['location_dest_id', '=', 9]]

             # filtre 
            Articles_PF_Sales = []

            if par.Get_SALE:

                dom_Sales =[['location_id', '=', company.Sales_location], ['date', 'month', 0],['state', '=', 'done'], ['location_dest_id', '=', 9]]
                # Champs à agréger
                fields_Sales = ['product_uom_qty']
                # Groupement par produit
                groupby_Sales = ['product_id']

                Articles_PF_Sales = models.execute_kw(
                    par.database,
                    request.session.get('uid', ''), 
                    request.session.get('pw', ''), 
                    'stock.move',
                    'read_group',
                    [dom_Sales, fields_Sales, groupby_Sales],
                    {
                        'context': {'lang': 'fr_FR'}
                    }
                )

            cleaned_result = {}
            for rec in Articles_PF_Sales:
                cleaned_result[rec['product_id'][0]]= rec['product_uom_qty']
            
            global result_dic_sales
            
            result_dic_sales[request.user.username]=cleaned_result
            #print("*******************************************")
           
            #print(cleaned_result)

            #************************** Production *********************************

            # ['|', '|', ['location_dest_id', '=', 420], ['location_dest_id', '=', 1894], ['location_dest_id', '=', 1596], ['date', 'month', 0], ['state', '=', 'done'], ['location_id', '=', 10]]
            
            
            dom_Productions = [['location_dest_id', '=', company.Sales_location], ['date', 'month', 0], ['state', '=', 'done'], ['location_id', '=', 10]]

            # Champs à agréger
            fields_Productions = ['product_uom_qty']
            # Groupement par produit
            groupby_Productions = ['product_id']
            Articles_PF_Productions = []

            if par.Get_PROD:
                Articles_PF_Productions = models.execute_kw(
                    par.database,
                    request.session.get('uid', ''), 
                    request.session.get('pw', ''), 
                    'stock.move',
                    'read_group',
                    [dom_Productions, fields_Productions, groupby_Productions],
                    {
                        'context': {'lang': 'fr_FR'}
                    }
                )

            cleaned_result_Productions = {}
            for rec in Articles_PF_Productions:
                cleaned_result_Productions[rec['product_id'][0]]= rec['product_uom_qty']
            
            global result_dic_Productions 
            
            result_dic_Productions[request.user.username]=cleaned_result_Productions

            #print(cleaned_result_Productions)
            #****************************************************************************************************************************************


            dom_SM = [('product_id.categ_id.parent_id.name', 'ilike', get_cat_pf(uid)),('product_id.sale_ok', '=', True),('product_min_qty', '>', 0)]
            dom_SM = [('product_id.id', 'in', Liste_PF_ids),('product_min_qty', '>', 0)]
            champs_SM = ['product_min_qty','product_id']
            global Stock_min_dic
            if par.prevision_ERP:
                Stock_min = models.execute_kw(
                    par.database, 
                    request.session.get('uid', ''), 
                    request.session.get('pw', ''),
                    'stock.rule',
                    'search_read',  # Odoo model name and method
                    [dom_SM],  # Domain for filtering the records (empty list fetches all)
                    {'fields': champs_SM}  # Fields you want to retrieve
                )
                Stock_min_dic[request.user.username]=Stock_min

            
            #**************** Get list of Bill of materiel ******************


            dom_BM = [('product_id.id', 'in', Liste_PF_ids)]
            champs_BM = [ 'id','code', 'product_qty', 'product_id','bom_line_ids','sequence','name']
            context1 = {'lang': 'en_US'}  # Example context
            global Boms_dic
            Boms = models.execute_kw(par.database,
                                     request.session.get('uid', ''), 
                                     request.session.get('pw', ''),
                                     'mrp.bom', 
                                     'search_read', 
                                     [dom_BM],
                                     {'fields': champs_BM, 'context': context1})
            
            print('marque:',request.session.get('marque', ''))
            dom_BM1 = [('product_id.marque_id.name', 'ilike', request.session.get('marque', '')),('sequence', '=', 0)]
            champs_BM = [ 'id','code', 'product_qty', 'product_id','bom_line_ids','sequence','name']
            context1 = {'lang': 'en_US'}  # Example context
            
            Boms1 = models.execute_kw(par.database,
                                     request.session.get('uid', ''), 
                                     request.session.get('pw', ''),
                                     'mrp.bom', 
                                     'search_read', 
                                     [dom_BM1],
                                     {'fields': champs_BM, 'context': context1})
            
            #print('boms lighting niveau 2',Boms1)
            Boms.extend(Boms1)
            Boms_dic[request.user.username]=Boms
            #print('boms lighting niveau 2',Boms)
            #print(Boms_dic[request.user.username])
            
            #**************** Get list of Bill of materiel lines ******************

            global Bom_Lines_dic
           
            champs_BOM_lines = ['product_id', 'reference_id', 'product_qty']
    
            for bom in Boms_dic[request.user.username]:
                bom_lines = models.execute_kw(par.database,
                                             request.session.get('uid', ''), 
                                             request.session.get('pw', ''),
                                             'mrp.bom.line',
                                             'read',
                                             [bom['bom_line_ids']],
                                             {'fields': champs_BOM_lines})
                x={
                    'bom_id':bom['id'],
                    'bom_lines':bom_lines
                }
                Bom_Lines.append(x)
            #print(Bom_Lines)
            Bom_Lines_dic[request.user.username]=Bom_Lines
            #print(Bom_Lines_dic[request.user.username][0])
            #components = get_all_components(Boms_dic[request.user.username], Bom_Lines_dic[request.user.username], 35801)
            #print(components)
            """ for cid, info in components.items():
                name = info['name'] or f"ID {cid}"
                print(f"{name} (ID {cid}) → {info['qty']}") """


            article_mp_ids_tmp = []

            for bl in  Bom_Lines_dic[request.user.username]:
                for art_id in bl['bom_lines']:
                    article_mp_ids_tmp.append(art_id['product_id'][0])            

            article_mp_ids = list(set(article_mp_ids_tmp))   
            #print(len(article_mp_ids))
            #print(article_mp_ids)

            #**************** Get list of composants ******************
            dom_MP = [['id','in',article_mp_ids]]
            champs_MP = ['id','default_code','name','qty_available','virtual_available','categ_id','sale_ok','purchase_ok']
            global Articles_MP_dic
            Articles_MP = models.execute_kw(
                par.database,
                request.session.get('uid', ''), 
                request.session.get('pw', ''),
                'product.product', 'search_read',  # Odoo model name and method
                [dom_MP],  # Domain for filtering the records (empty list fetches all)
                {'fields': champs_MP,  # Champs à récupérer
                 'context': {'lang': 'fr_FR'}}  # Fields you want to retrieve
            )
            Articles_MP_dic[request.user.username]=Articles_MP

            dom_MP_imp = [('categ_id.name', 'ilike',request.session.get('cat_imp', ''))]
            champs_MP_imp = ['id','default_code','name','qty_available','virtual_available','categ_id','sale_ok','purchase_ok']
            global Articles_MP_dic_imp
            Articles_MP_imp = models.execute_kw(
                par.database,
                request.session.get('uid', ''), 
                request.session.get('pw', ''),
                'product.product', 'search_read',  # Odoo model name and method
                [dom_MP_imp],  # Domain for filtering the records (empty list fetches all)
                {'fields': champs_MP_imp,  # Champs à récupérer
                 'context': {'lang': 'fr_FR'}}  # Fields you want to retrieve
            )
            Articles_MP_dic_imp[request.user.username]=Articles_MP_imp

            #print('hhhhhhh',Articles_MP_dic_imp[request.user.username])
            Init_PRG(request)
            return redirect('produits:home')
            
            
        else:
            messages.error(request, "Nom d'utilisateur ou mot de passe incorrect")

    return render(request, 'login.html')



def get_all_components_by_bom(boms, bom_lines, bom_id, qty=1.0, result=None):
    """
    Retourne un dict {prod_id: {'name':..., 'qty':...}} des composants finaux nécessaires
    pour `qty` unités du produit fabriqué par la nomenclature `bom_id`.

    - boms : liste de BOMs (format Odoo : product_id = [id, name], product_qty, id, ...)
    - bom_lines : liste [{'bom_id': ..., 'bom_lines': [ { 'product_id': [id,name], 'product_qty':..., ... }, ... ]}]
    - bom_id : ID de la nomenclature principale (mrp.bom.id)
    - qty : quantité de produit fini à produire (défaut 1.0)
    """

    if result is None:
        result = {}

    # Trouver la nomenclature principale
    bom = next((b for b in boms if b['id'] == bom_id), None)
    if not bom:
        print(f"Aucune nomenclature trouvée avec id={bom_id}")
        return result

    product_id = bom['product_id'][0]
    product_name = bom['product_id'][1].strip()
    bom_qty = float(bom.get('product_qty') or 1.0)
    if bom_qty == 0:
        bom_qty = 1.0  # sécurité

    # Récupérer les lignes associées
    lines_entry = next((l for l in bom_lines if l['bom_id'] == bom_id), None)
    if not lines_entry or not lines_entry.get('bom_lines'):
        # Si pas de lignes, c’est un composant final
        if product_id not in result:
            result[product_id] = {'name': product_name, 'qty': 0.0}
        result[product_id]['qty'] += qty
        return result

    for line in lines_entry['bom_lines']:
        comp_id = line['product_id'][0]
        comp_name = line['product_id'][1].strip()
        line_qty = float(line.get('product_qty') or 0.0)

        # Quantité de composant pour la quantité demandée
        comp_total_needed = qty * (line_qty / bom_qty)

        # Vérifie si ce composant a sa propre nomenclature (SF)
        sub_bom = next((b for b in boms if b['product_id'][0] == comp_id), None)
        if sub_bom:
            # Appel récursif sur le sous-produit
            get_all_components_by_bom(boms, bom_lines, sub_bom['id'], comp_total_needed, result)
        else:
            # C’est un composant final
            if comp_id not in result:
                result[comp_id] = {'name': comp_name, 'qty': 0.0}
            result[comp_id]['qty'] += comp_total_needed

    return result


def get_subassemblies_with_bom(boms, bom_lines, bom_id, result=None):
    """
    Retourne un dict des SF (sous-ensembles) sous la forme :
    {
        sf_product_id: {
            'name': <nom du SF>,
            'bom_id': <id de la nomenclature SF>
        },
        ...
    }

    - boms : liste des BOMs (mrp.bom)
    - bom_lines : liste des lignes [{'bom_id': ..., 'bom_lines': [ {...}, ... ]}]
    - bom_id : ID de la BOM de départ (PF)
    """

    if result is None:
        result = {}

    # Trouver la BOM principale
    bom = next((b for b in boms if b['id'] == bom_id), None)
    if not bom:
        return result

    # Lignes de cette BOM
    lines_entry = next((l for l in bom_lines if l['bom_id'] == bom_id), None)
    if not lines_entry or not lines_entry.get('bom_lines'):
        return result

    for line in lines_entry['bom_lines']:
        comp_id = line['product_id'][0]
        comp_name = (line['product_id'][1] or '').strip()

        # Vérifier si ce composant a une BOM → c'est un SF
        sub_bom = next((b for b in boms if b['product_id'][0] == comp_id), None)
        if sub_bom:
            # Ajouter / mettre à jour dans le dict résultat
            result[comp_id] = {
                'name': comp_name,
                'bom_id': sub_bom['id'],
            }

            # Récursif : chercher les SF sous ce SF
            get_subassemblies_with_bom(boms, bom_lines, sub_bom['id'], result)

    return result



def get_all_components_by_bom_V2(boms, bom_lines, bom_id, qty=1.0, result=None, parent_product_id=None, parent_bom_id=None):
    """
    Retourne un dict {prod_id: {'name':..., 'qty':..., 'parent_product_id':..., 'parent_bom_id':...}}
    des composants finaux nécessaires pour `qty` unités du produit fabriqué par la nomenclature `bom_id`.

    - boms : liste de BOMs (format Odoo : product_id = [id, name], product_qty, id, ...)
    - bom_lines : liste [{'bom_id': ..., 'bom_lines': [ { 'product_id': [id,name], 'product_qty':..., ... }, ... ]}]
    - bom_id : ID de la nomenclature principale (mrp.bom.id)
    - qty : quantité de produit fini à produire (défaut 1.0)
    - parent_product_id : ID du produit parent (pour traçabilité)
    - parent_bom_id : ID de la nomenclature parent
    """

    if result is None:
        result = {}

    # Trouver la nomenclature principale
    bom = next((b for b in boms if b['id'] == bom_id), None)
    if not bom:
        print(f"Aucune nomenclature trouvée avec id={bom_id}")
        return result

    product_id = bom['product_id'][0]
    product_name = bom['product_id'][1].strip()
    bom_qty = float(bom.get('product_qty') or 1.0)
    if bom_qty == 0:
        bom_qty = 1.0  # sécurité

    # Récupérer les lignes associées
    lines_entry = next((l for l in bom_lines if l['bom_id'] == bom_id), None)
    if not lines_entry or not lines_entry.get('bom_lines'):
        # Pas de sous-composants
        if product_id not in result:
            result[product_id] = {
                'name': product_name,
                'qty': 0.0,
                'parent_product_id': parent_product_id,
                'parent_bom_id': parent_bom_id,
            }
        result[product_id]['qty'] += qty
        return result

    # Parcours des lignes de nomenclature
    for line in lines_entry['bom_lines']:
        comp_id = line['product_id'][0]
        comp_name = line['product_id'][1].strip()
        line_qty = float(line.get('product_qty') or 0.0)

        comp_total_needed = qty * (line_qty / bom_qty)

        # Vérifie si ce composant a une sous-nomenclature
        sub_bom = next((b for b in boms if b['product_id'][0] == comp_id), None)
        if sub_bom:
            # Appel récursif pour le sous-produit
            get_all_components_by_bom(
                boms,
                bom_lines,
                sub_bom['id'],
                comp_total_needed,
                result,
                parent_product_id=product_id,
                parent_bom_id=bom_id
            )
        else:
            # C’est un composant final
            if comp_id not in result:
                result[comp_id] = {
                    'name': comp_name,
                    'qty': 0.0,
                    'parent_product_id': product_id,
                    'parent_bom_id': bom_id,
                }
            result[comp_id]['qty'] += comp_total_needed

    return result





def username_erp_name(request):
    global username_erp
    return HttpResponse(username_erp)
    




def Prevision_vente(request):


    context = {
        
        'access':get_access(request.user.username),
       
    }
 
    return render(request,'prevision_import.html',context) 

def Save_Stock_Prevu_view(request):


    context = {
        
    'access':get_access(request.user.username),
       
    }

    return render(request,'stock_init_import.html',context) 

def Get_Stock_Init(request,product_code):
    date_pr = date.today()
    annee = date_pr.year
    mois = date_pr.month

    try:
    # Recherche de l'enregistrement correspondant
        record = prevsion_vente.objects.get(Product_Code=product_code, Annee=annee,company=request.session.get('current_company_id', ''))

        # Récupération dynamique du champ (_1, _2, ..., _12)
        field_name = f"SI_{mois}"
        quantite = getattr(record, field_name, 0)

        return quantite

    except prevsion_vente.DoesNotExist:
        return 0

        
    
      

def Save_Stock_Prevu(request):
    
    date_pr = date.today()
    annee = date_pr.year
    mois = date_pr.month
    produits = list(prevsion_vente.objects.filter(Annee=annee)
                    .values_list('Product_Code', flat=True))

    for pf in Articles_PF_dic.get(request.user.username, []):
        code = pf['default_code']
        stock = pf['virtual_available']
        if code in produits:
            record = prevsion_vente.objects.get(Product_Code=code, Annee=annee,company=request.session.get('current_company_id', ''))
            setattr(record, f"SI_{mois}", stock)
            record.save()

    return JsonResponse({"message":"Stock initial chargé avec suucès"})

def Import_Stock_Init(request):
    if request.method == 'POST':
        annee = int(request.POST.get('annee'))
        mois = int(request.POST.get('mois'))  # exemple : 10
        data_json = request.POST.get('articles')

        try:
            articles = json.loads(data_json)

            for art in articles:

                record = prevsion_vente.objects.get(Product_Code=art['code'], Annee=annee,company=request.session.get('current_company_id', ''))
                setattr(record, f"SI_{mois}", art['quantite'])
                record.save()

        except json.JSONDecodeError:
            return JsonResponse({"error": "Invalid JSON"}, status=400)

    return JsonResponse({"message": 1})

def get_prevesion_quantity(request, product_code, annee, mois):
    """
    Retourne la quantité prévue pour un produit, une année et un mois donnés.
    Exemple d'appel : /get_quantity/P-12345/2025/10/
    """

    # Vérification de validité du mois
    if mois < 1 or mois > 12:
        return JsonResponse({'error': 'Le mois doit être entre 1 et 12'}, status=400)

    try:
        # Recherche de l'enregistrement correspondant
        record = prevsion_vente.objects.get(Product_Code=product_code, Annee=annee,company=request.session.get('current_company_id', ''))

        # Récupération dynamique du champ (_1, _2, ..., _12)
        field_name = f"_{mois}"
        quantite = getattr(record, field_name, 0)

        return quantite

    except prevsion_vente.DoesNotExist:
        return 0



def refresh_data(request):
    par = get_paramettre(request.user.username)
    print(par.database)
    
    models = xmlrpc.client.ServerProxy(f'{par.link_db}/xmlrpc/2/object')

    
    #print(uid)
    # save categorie pf in session
    request.session['cat_pf'] = par.cat_parent_pf
    # save categorie IMP in session
    request.session['cat_imp'] = par.cat_imporation
    print('cat imp',request.session['cat_imp'])
    # save uid in session
    
    request.session['BOM'] = par.Bom
    request.session['Sale_ok'] = par.Sale_ok

    
    #print(request.session.get('pw', ''),request.session.get('cat_pf', ''),request.session.get('cat_imp', ''),request.session.get('uid', ''))

    # [['date', 'month', 0], ['location_dest_id', '=', 9]]
    # ['|', '|', ['location_dest_id', '=', 420], ['location_dest_id', '=', 1894], ['location_dest_id', '=', 1596], ['date', 'month', 0], ['location_id', '!=', 9], ['location_id', '=', 10]]
    champs_CAT = ['id','name','parent_id']
    context1 = {'lang': 'en_US'}
    dom_cat = [('name', 'ilike', request.session.get('cat_imp', ''))]


    global categories,categories_dic
    categories = models.execute_kw(par.database,
                                    request.session.get('uid', ''), 
                                    request.session.get('pw', ''),
                                    'product.category',
                                    'search_read',
                                    [dom_cat],
                                    {'fields': champs_CAT, 'context': context1})
    
    # save categorie imp id  in session
    request.session['cat_imp_id'] = categories[0]['id']

    #categories_dic[request.user.username]=categories
    #print(categories[0]['id'])

    user = models.execute_kw(par.database, 
                                request.session.get('uid', ''), 
                                request.session.get('pw', ''),
                                'res.users',
                                'read',
                                [request.session.get('uid', '')], 
                                {'fields': ['company_id','name']})
    
    
    #print(user['company_id'][0])
    # save id current company  in session
    request.session['current_company_id'] = user['company_id'][0]
    print(request.session['current_company_id'])

    company = get_company_byid(int(request.session['current_company_id']))
    #**************** Get list of final product ******************

    # filtre 
    if request.session['BOM']== True:
        if request.session['Sale_ok']== True:
    
            dom_PF = [('categ_id.parent_id.name', 'ilike',request.session.get('cat_pf', '')),('sale_ok', '=', True),('active', '=', True),('bom_ids.id', '!=', False)]
        else:
            dom_PF = [('categ_id.parent_id.name', 'ilike',request.session.get('cat_pf', '')),('sale_ok', '=', False),('purchase_ok', '=', False),('active', '=', True),('bom_ids.id', '!=', False)]
    else:
        if request.session['Sale_ok']== True:
            dom_PF = [('categ_id.parent_id.name', 'ilike',request.session.get('cat_pf', '')),('sale_ok', '=', True),('active', '=', True)]
        else:
            dom_PF = [('categ_id.parent_id.name', 'ilike',request.session.get('cat_pf', '')),('sale_ok', '=', False),('purchase_ok', '=', False),('active', '=', True)]



    # les champs a affichés
    champs_PF = ['id','default_code','name','qty_available','virtual_available']
    global Articles_PF_dic
    Articles_PF = models.execute_kw(
        par.database,
        request.session.get('uid', ''), 
        request.session.get('pw', ''),
        'product.product',
        'search_read',  # Odoo model name and method
        [dom_PF],  # Domain for filtering the records (empty list fetches all)
        {
            'fields': champs_PF,  # Champs à récupérer
            'context': {'lang': 'fr_FR','location':company.Sales_location}
        }  # Fields you want to retrieve
    )
    #print(Articles_PF)
    Articles_PF_dic[request.user.username]=Articles_PF
    
    Liste_PF_ids = [i['id'] for i in Articles_PF_dic[request.user.username]]
    #print(Liste_PF_ids)

    # ********************* Sales **********************************

    # [['date', 'month', 0], ['location_dest_id', '=', 9]]

        # filtre 
    

    dom_Sales =[['location_id', '=', company.Sales_location], ['date', 'month', 0],['state', '=', 'done'], ['location_dest_id', '=', 9]]
    # Champs à agréger
    fields_Sales = ['product_uom_qty']
    # Groupement par produit
    groupby_Sales = ['product_id']

    Articles_PF_Sales = models.execute_kw(
        par.database,
        request.session.get('uid', ''), 
        request.session.get('pw', ''), 
        'stock.move',
        'read_group',
        [dom_Sales, fields_Sales, groupby_Sales],
        {
            'context': {'lang': 'fr_FR'}
        }
    )

    cleaned_result = {}
    for rec in Articles_PF_Sales:
        cleaned_result[rec['product_id'][0]]= rec['product_uom_qty']
    
    global result_dic_sales
    
    result_dic_sales[request.user.username]=cleaned_result
    #print("*******************************************")
    
    #print(cleaned_result)

    #************************** Production *********************************

    # ['|', '|', ['location_dest_id', '=', 420], ['location_dest_id', '=', 1894], ['location_dest_id', '=', 1596], ['date', 'month', 0], ['state', '=', 'done'], ['location_id', '=', 10]]
    
    
    dom_Productions = [['location_dest_id', '=', company.Sales_location], ['date', 'month', 0], ['state', '=', 'done'], ['location_id', '=', 10]]

    # Champs à agréger
    fields_Productions = ['product_uom_qty']
    # Groupement par produit
    groupby_Productions = ['product_id']

    Articles_PF_Productions = models.execute_kw(
        par.database,
        request.session.get('uid', ''), 
        request.session.get('pw', ''), 
        'stock.move',
        'read_group',
        [dom_Productions, fields_Productions, groupby_Productions],
        {
            'context': {'lang': 'fr_FR'}
        }
    )

    cleaned_result_Productions = {}
    for rec in Articles_PF_Productions:
        cleaned_result_Productions[rec['product_id'][0]]= rec['product_uom_qty']
    
    global result_dic_Productions 
    
    result_dic_Productions[request.user.username]=cleaned_result_Productions

    #print(cleaned_result_Productions)
    #****************************************************************************************************************************************


    dom_SM = [('product_id.categ_id.parent_id.name', 'ilike', get_cat_pf(request.session.get('uid', ''))),('product_id.sale_ok', '=', True),('product_min_qty', '>', 0)]
    dom_SM = [('product_id.id', 'in', Liste_PF_ids),('product_min_qty', '>', 0)]
    champs_SM = ['product_min_qty','product_id']
    global Stock_min_dic
    if par.prevision_ERP:
        Stock_min = models.execute_kw(
            par.database, 
            request.session.get('uid', ''), 
            request.session.get('pw', ''),
            'stock.rule',
            'search_read',  # Odoo model name and method
            [dom_SM],  # Domain for filtering the records (empty list fetches all)
            {'fields': champs_SM}  # Fields you want to retrieve
        )
        Stock_min_dic[request.user.username]=Stock_min

    
    #**************** Get list of Bill of materiel ******************


    dom_BM = [('product_id.id', 'in', Liste_PF_ids)]
    champs_BM = [ 'id','code', 'product_qty', 'product_id','bom_line_ids','sequence','name']
    context1 = {'lang': 'en_US'}  # Example context
    global Boms_dic
    Boms = models.execute_kw(par.database,
                                request.session.get('uid', ''), 
                                request.session.get('pw', ''),
                                'mrp.bom', 
                                'search_read', 
                                [dom_BM],
                                {'fields': champs_BM, 'context': context1})
    Boms_dic[request.user.username]=Boms
    
    #print(Boms_dic[request.user.username])
    
    #**************** Get list of Bill of materiel lines ******************

    global Bom_Lines_dic
    
    champs_BOM_lines = ['product_id', 'product_qty']

    for bom in Boms_dic[request.user.username]:
        bom_lines = models.execute_kw(par.database,
                                        request.session.get('uid', ''), 
                                        request.session.get('pw', ''),
                                        'mrp.bom.line',
                                        'read',
                                        [bom['bom_line_ids']],
                                        {'fields': champs_BOM_lines})
        x={
            'bom_id':bom['id'],
            'bom_lines':bom_lines
        }
        Bom_Lines.append(x)

    Bom_Lines_dic[request.user.username]=Bom_Lines
    #print(Bom_Lines_dic[request.user.username][0])

    article_mp_ids_tmp = []

    for bl in  Bom_Lines_dic[request.user.username]:
        for art_id in bl['bom_lines']:
            article_mp_ids_tmp.append(art_id['product_id'][0])            

    article_mp_ids = list(set(article_mp_ids_tmp))   
    #print(len(article_mp_ids))
    #print(article_mp_ids)

    #**************** Get list of composants ******************
    dom_MP = [['id','in',article_mp_ids]]
    champs_MP = ['id','default_code','name','qty_available','virtual_available','categ_id','sale_ok','purchase_ok']
    global Articles_MP_dic
    Articles_MP = models.execute_kw(
        par.database,
        request.session.get('uid', ''), 
        request.session.get('pw', ''),
        'product.product', 'search_read',  # Odoo model name and method
        [dom_MP],  # Domain for filtering the records (empty list fetches all)
        {'fields': champs_MP,  # Champs à récupérer
            'context': {'lang': 'fr_FR'}}  # Fields you want to retrieve
    )
    Articles_MP_dic[request.user.username]=Articles_MP

    dom_MP_imp = [('categ_id.name', 'ilike',request.session.get('cat_imp', ''))]
    champs_MP_imp = ['id','default_code','name','qty_available','virtual_available','categ_id','sale_ok','purchase_ok']
    global Articles_MP_dic_imp
    Articles_MP_imp = models.execute_kw(
        par.database,
        request.session.get('uid', ''), 
        request.session.get('pw', ''),
        'product.product', 'search_read',  # Odoo model name and method
        [dom_MP_imp],  # Domain for filtering the records (empty list fetches all)
        {'fields': champs_MP_imp,  # Champs à récupérer
            'context': {'lang': 'fr_FR'}}  # Fields you want to retrieve
    )
    Articles_MP_dic_imp[request.user.username]=Articles_MP_imp

    #print('hhhhhhh',Articles_MP_dic_imp[request.user.username])
    Init_PRG(request)
    return redirect('produits:home')
    
    
def Couverture_By_product(request, product_code, stock):
    """
    Retourne la couverture de stock (en mois) pour un article donné
    à partir des prévisions mensuelles de vente.
    """
    try:
        today = date.today()
        company_id = request.session.get('current_company_id', '')

        # Récupération des prévisions futures du produit
        records = list(
            prevsion_vente.objects.filter(
                Product_Code=product_code,
                Annee__gte=today.year,
                company=company_id
            ).order_by('Annee')
        )

        if not records:
            return 0

        cpt = 0  # Nombre de mois couverts
        quantite = 0
        date_current = today
        jours_restants = jours_ouvrables_restants()
        remaining_qty = stock  # Stock au début

        while stock > 0:
            record = next((r for r in records if r.Annee == date_current.year), None)
            if not record:
                break  # plus de prévisions disponibles

            champ = f"_{date_current.month}"
            quantite = getattr(record, champ, 0)

            if quantite == 0:
                # Si aucune prévision pour ce mois → passer au mois suivant
                date_current += relativedelta(months=1)
                continue

            # Sauvegarde du stock avant consommation
            remaining_qty = stock

            # Consommation du stock
            if date_current.month == today.month:
                stock -= quantite / 22 * jours_restants  # proportion du mois courant
            else:
                stock -= quantite

            # Si le stock devient négatif → rupture au milieu du mois
            if stock <= 0:
                break

            # Passer au mois suivant
            date_current += relativedelta(months=1)
            cpt += 1


        print('remaining_qty',remaining_qty,'quantite',quantite)
        # --- Calcul de la couverture finale ---
        if quantite > 0:
            # On ajoute la fraction du dernier mois couvert partiellement
            couverture = cpt + max(remaining_qty / quantite, 0)
            return round(couverture, 2)
        else:
            return cpt

    except Exception as e:
        print("Erreur Couverture_By_product:", e)
        return 0



def prevesion_global_article(product_code, nbr_mois):
    """Retourne la somme annuelle d'un article pour toutes les années >= annee."""
    date_str = date.today()

    prevs = prevsion_vente.objects.filter(Product_Code=product_code, Annee__gte=date_str.year)
    
    total = 0
    
    for prev in prevs:
        total += sum(getattr(prev, f'_{i}', 0) for i in range(1, 13))
    
    return int(total)



def prevesion_moyenne(product_code, annee):
    """Retourne la moyenne annuelle d'un article et d'une année donnés."""
    try:
        prev = prevsion_vente.objects.get(Product_Code=product_code, Annee=annee)
        total = sum(getattr(prev, f'_{i}', 0) for i in range(1, 13))
        moyenne = total / 12
        return int(moyenne)
    except prevsion_vente.DoesNotExist:
        return 0  # ou None selon ton besoin


def couverture_pf(request,*args,**kwargs):
    name_erp = username_erp_name(request)
    form = ArticleFilterForm(request.GET or None)
    #global result
    print('pm')
    global PF_SM_dic
    PF_sf = []
    date_pr = date.today()
    par = get_paramettre(request.user.username)
    if par.prevision_ERP:
        for pf in Articles_PF_dic[request.user.username]:
            for sm in Stock_min_dic[request.user.username]:
                if pf['id']==sm['product_id'][0]:
                    prd_id = pf['id']
                    prd_code = pf['default_code']
                    prd_name = pf['name']
                    prd_avb_st = pf['qty_available']
                    prd_vrt_st = pf['virtual_available']
                    prd_min = sm['product_min_qty']
                    prevision_avrg = sm['product_min_qty']
                    prd_can_prd_max = can_prd_global_IMP(prd_id,request)
                    prd_ecart = prd_vrt_st - prevision_avrg
                    prd_couvrt = 0
                    
                    if prd_vrt_st <=0:
                        prd_couvrt = 0
                    
                    else:
                        if prevision_avrg==0:
                            prd_couvrt = 0
                        else:
                            prd_couvrt = prd_vrt_st/prevision_avrg

                    combined_item = {
                                    'id':prd_id,
                                    'default_code':prd_code,
                                    'name':prd_name,
                                    'qty_available':prd_avb_st,
                                    'virtual_available':prd_vrt_st,
                                    'product_min_qty':prd_min,
                                    'previson_avrg':prevision_avrg,
                                    'ecar':prd_ecart,
                                    'couvert':prd_couvrt,
                                    'prd_max':prd_can_prd_max,
                                }
                    PF_sf.append(combined_item)
    else:
        for pf in Articles_PF_dic[request.user.username]:            
                prd_id = pf['id']
                prd_code = pf['default_code']
                prd_name = pf['name']
                prd_avb_st = pf['qty_available']
                prd_vrt_st = pf['virtual_available']
                prd_min = get_prevesion_quantity(request,pf['default_code'],date_pr.year,date_pr.month)
                prevision_avrg = prevesion_moyenne(pf['default_code'],date_pr.year)
                print('code pf:',pf['default_code'],'couverture:',Couverture_By_product(request,prd_code,prd_vrt_st))
                prd_can_prd_max = can_prd_global_IMP(prd_id,request)
                
                prd_ecart = prd_vrt_st - prevision_avrg
                prd_couvrt = 0
                    
                if prd_vrt_st <=0:
                    prd_couvrt = 0
                
                else:
                    if prevision_avrg==0:
                        prd_couvrt = 0
                    else:
                        prd_couvrt = prd_vrt_st/prevision_avrg

                combined_item = {
                                'id':prd_id,
                                'default_code':prd_code,
                                'name':prd_name,
                                'qty_available':prd_avb_st,
                                'virtual_available':prd_vrt_st,
                                'product_min_qty':prd_min,
                                'previson_avrg':prevision_avrg,
                                'ecar':prd_ecart,
                                'couvert':prd_couvrt,
                                'prd_max':prd_can_prd_max,
                            }
                PF_sf.append(combined_item)

    PF_SM_dic[request.user.username] =PF_sf
    
    if form.is_valid():
        if form.cleaned_data['default_code']:            
            PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if form.cleaned_data['default_code'].lower() in art['default_code'].lower() or form.cleaned_data['default_code'].lower() in art['name'].lower()] 
        if form.cleaned_data['chiffre']:
            if form.cleaned_data['regle']:
                if form.cleaned_data['regle'] == 'egal': 
                    PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if art[form.cleaned_data['chiffre']] == form.cleaned_data['val']]
                elif form.cleaned_data['regle'] =='notegal': 
                    PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if art[form.cleaned_data['chiffre']] != form.cleaned_data['val']] 
                elif form.cleaned_data['regle'] =='sup': 
                    PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if art[form.cleaned_data['chiffre']] > form.cleaned_data['val']] 
                elif form.cleaned_data['regle'] =='inf': 
                    PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if art[form.cleaned_data['chiffre']] < form.cleaned_data['val']]
                elif form.cleaned_data['regle'] =='supegal': 
                    PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if art[form.cleaned_data['chiffre']] >= form.cleaned_data['val']] 
                else:
                    PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if art[form.cleaned_data['chiffre']] <= form.cleaned_data['val']]
                    
                       
    PF_SM_dic[request.user.username] = sorted(PF_SM_dic[request.user.username],key=lambda art: art["default_code"])

    #Save_Stock_Prevu(request)
    context = {
        'produits' : PF_SM_dic[request.user.username],
        'nom':'Produits de la boutique',
        'form': form,
        'name_erp':request.session.get('current_company_id', ''),
        'nbr_result':len(PF_SM_dic[request.user.username]),
        'access':get_access(request.user.username),
        }
    
    return render(request,'couverture_pf.html',context)

     
def pdp_menseuel(request,*args,**kwargs):

    name_erp = username_erp_name(request)
    form = ArticleFilterForm(request.GET or None)
    #global result
    print('pdp m')
    global PF_SM_dic
    PF_sf = []
    date_pr = date.today()
    par = get_paramettre(request.user.username)
    if par.prevision_ERP:
        for pf in Articles_PF_dic[request.user.username]:
            for sm in Stock_min_dic[request.user.username]:
                if pf['id']==sm['product_id'][0]:
                    prd_id = pf['id']
                    prd_code = pf['default_code']
                    prd_name = pf['name']
                    prd_avb_st = pf['qty_available']
                    prd_vrt_st = pf['virtual_available']
                    prd_min = sm['product_min_qty']
                    
                    prd_can_prd_max = can_prd_global_IMP(prd_id,request)
                    
                    stock_init = Get_Stock_Init(request,pf['default_code'])

                    prd_ecart = stock_init-prd_min

                    prd_couvrt = 0
                    
                    if stock_init<=0:
                        prd_couvrt = 0
                    else:
                        if prd_min==0:
                            prd_couvrt = 0
                        else:
                            prd_couvrt = stock_init/prd_min

                    combined_item = {
                                    'id':prd_id,
                                    'default_code':prd_code,
                                    'name':prd_name,
                                    'qty_available':prd_avb_st,
                                    'virtual_available':prd_vrt_st,
                                    'product_min_qty':prd_min,
                                    'ecar':prd_ecart,
                                    'couvert':prd_couvrt,
                                    'prd_max':prd_can_prd_max,
                                    'stock_init':stock_init,
                                }
                    PF_sf.append(combined_item)
    else:
        for pf in Articles_PF_dic[request.user.username]:            
                prd_id = pf['id']
                prd_code = pf['default_code']
                prd_name = pf['name']
                prd_avb_st = pf['qty_available']
                prd_vrt_st = pf['virtual_available']
                prd_min = get_prevesion_quantity(request,pf['default_code'],date_pr.year,date_pr.month)
                prd_can_prd_max = can_prd_global_IMP(prd_id,request)
                stock_init = Get_Stock_Init(request,pf['default_code'])

                
                prd_ecart = stock_init-prd_min

                prd_couvrt = 0
                if stock_init<=0:
                    prd_couvrt = 0
                else:
                    if prd_min==0:
                        prd_couvrt = 0
                    else:
                        prd_couvrt = stock_init/prd_min

                
                combined_item = {
                                    'id':prd_id,
                                    'default_code':prd_code,
                                    'name':prd_name,
                                    'qty_available':prd_avb_st,
                                    'virtual_available':prd_vrt_st,
                                    'product_min_qty':prd_min,
                                    'ecar':prd_ecart,
                                    'couvert':prd_couvrt,
                                    'prd_max':prd_can_prd_max,
                                    'stock_init':stock_init,
                                }
                PF_sf.append(combined_item)

    PF_SM_dic[request.user.username] =PF_sf
    global result_prd_dic
    result_prd_dic[request.user.username] =PF_sf
    if form.is_valid():
        if form.cleaned_data['default_code']:            
            PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if form.cleaned_data['default_code'].lower() in art['default_code'].lower() or form.cleaned_data['default_code'].lower() in art['name'].lower()] 
        if form.cleaned_data['chiffre']:
            if form.cleaned_data['regle']:
                if form.cleaned_data['regle'] == 'egal': 
                    PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if art[form.cleaned_data['chiffre']] == form.cleaned_data['val']]
                elif form.cleaned_data['regle'] =='notegal': 
                    PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if art[form.cleaned_data['chiffre']] != form.cleaned_data['val']] 
                elif form.cleaned_data['regle'] =='sup': 
                    PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if art[form.cleaned_data['chiffre']] > form.cleaned_data['val']] 
                elif form.cleaned_data['regle'] =='inf': 
                    PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if art[form.cleaned_data['chiffre']] < form.cleaned_data['val']]
                elif form.cleaned_data['regle'] =='supegal': 
                    PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if art[form.cleaned_data['chiffre']] >= form.cleaned_data['val']] 
                else:
                    PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if art[form.cleaned_data['chiffre']] <= form.cleaned_data['val']]
                    
                       
    PF_SM_dic[request.user.username] = sorted(PF_SM_dic[request.user.username],key=lambda art: art["default_code"])

    #Save_Stock_Prevu(request)
    context = {
        'produits' : PF_SM_dic[request.user.username],
        'nom':'Produits de la boutique',
        'form': form,
        'name_erp':request.session.get('current_company_id', ''),
        'nbr_result':len(PF_SM_dic[request.user.username]),
        'access':get_access(request.user.username),
        }
    
    return render(request,'pdp_menseuel.html',context)

def pdp_journalier(request,*args,**kwargs):

    name_erp = username_erp_name(request)
    form = ArticleFilterForm(request.GET or None)
    #global result
    print('suivi')
    global PF_SM_dic
    PF_sf = []
    date_pr = date.today()
    par = get_paramettre(request.user.username)
    if par.prevision_ERP:
        for pf in Articles_PF_dic[request.user.username]:
            for sm in Stock_min_dic[request.user.username]:
                if pf['id']==sm['product_id'][0]:
                    prd_id = pf['id']
                    prd_code = pf['default_code']
                    prd_name = pf['name']
                    prd_avb_st = pf['qty_available']
                    prd_vrt_st = pf['virtual_available']
                    prd_min = sm['product_min_qty']
                    prd_can_prd_max = can_prd_global_IMP(prd_id,request)
                    
                    productions = result_dic_Productions[request.user.username].get(prd_id,0)
                    stock_init = Get_Stock_Init(request,pf['default_code'])

                    prd_ecart_init = stock_init - prd_min
                    prd_ecart = productions - abs(prd_ecart_init)

                    if prd_ecart_init == 0 :
                        prd_couvrt = 0
                    else:
                        if prd_ecart_init ==0:
                            prd_couvrt = 0
                        else:
                            prd_couvrt = productions/abs(prd_ecart_init)*100
                    
                    combined_item = {
                                    'id':prd_id,
                                    'default_code':prd_code,
                                    'name':prd_name,
                                    'qty_available':prd_avb_st,
                                    'virtual_available':prd_vrt_st,
                                    'stock_init':stock_init,
                                    'product_min_qty':prd_ecart_init,                        
                                    'productions':productions,      
                                    'ecar':prd_ecart,
                                    'couvert':prd_couvrt,
                                    'prd_max':prd_can_prd_max,
                                }
                    PF_sf.append(combined_item)
    else:
        for pf in Articles_PF_dic[request.user.username]:            
                prd_id = pf['id']
                prd_code = pf['default_code']
                prd_name = pf['name']
                prd_avb_st = pf['qty_available']
                prd_vrt_st = pf['virtual_available']
                prd_min = get_prevesion_quantity(request,pf['default_code'],date_pr.year,date_pr.month)
                
                prd_can_prd_max = can_prd_global_IMP(prd_id,request)
                
                productions = result_dic_Productions[request.user.username].get(prd_id,0)
                stock_init = Get_Stock_Init(request,pf['default_code'])
                
                prd_ecart_init = stock_init - prd_min
                prd_ecart = productions - abs(prd_ecart_init)

                if prd_ecart_init == 0 :
                    prd_couvrt = 0
                else:
                    if prd_ecart_init ==0:
                        prd_couvrt = 0
                    else:
                        prd_couvrt = productions/abs(prd_ecart_init)*100
                
                combined_item = {
                                'id':prd_id,
                                'default_code':prd_code,
                                'name':prd_name,
                                'qty_available':prd_avb_st,
                                'virtual_available':prd_vrt_st,
                                'stock_init':stock_init,
                                'product_min_qty':prd_ecart_init,
                                'productions':productions,      
                                'ecar':prd_ecart,
                                'couvert':prd_couvrt,
                                'prd_max':prd_can_prd_max,
                            }
                PF_sf.append(combined_item)

    PF_SM_dic[request.user.username] =PF_sf
    
    if form.is_valid():
        if form.cleaned_data['default_code']:            
            PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if form.cleaned_data['default_code'].lower() in art['default_code'].lower() or form.cleaned_data['default_code'].lower() in art['name'].lower()] 
        if form.cleaned_data['chiffre']:
            if form.cleaned_data['regle']:
                if form.cleaned_data['regle'] == 'egal': 
                    PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if art[form.cleaned_data['chiffre']] == form.cleaned_data['val']]
                elif form.cleaned_data['regle'] =='notegal': 
                    PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if art[form.cleaned_data['chiffre']] != form.cleaned_data['val']] 
                elif form.cleaned_data['regle'] =='sup': 
                    PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if art[form.cleaned_data['chiffre']] > form.cleaned_data['val']] 
                elif form.cleaned_data['regle'] =='inf': 
                    PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if art[form.cleaned_data['chiffre']] < form.cleaned_data['val']]
                elif form.cleaned_data['regle'] =='supegal': 
                    PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if art[form.cleaned_data['chiffre']] >= form.cleaned_data['val']] 
                else:
                    PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if art[form.cleaned_data['chiffre']] <= form.cleaned_data['val']]
                    
                       
    PF_SM_dic[request.user.username] = sorted(PF_SM_dic[request.user.username],key=lambda art: art["default_code"])

    #Save_Stock_Prevu(request)
    context = {
        'produits' : PF_SM_dic[request.user.username],
        'nom':'Produits de la boutique',
        'form': form,
        'name_erp':request.session.get('current_company_id', ''),
        'nbr_result':len(PF_SM_dic[request.user.username]),
        'access':get_access(request.user.username),
        }
    
    return render(request,'pdp_journalier.html',context)


def index(request,*args,**kwargs):

    name_erp = username_erp_name(request)
    form = ArticleFilterForm(request.GET or None)
    #global result

    global PF_SM_dic
    PF_sf = []
    date_pr = date.today()
    par = get_paramettre(request.user.username)
    if par.prevision_ERP:
        for pf in Articles_PF_dic[request.user.username]:
            for sm in Stock_min_dic[request.user.username]:
                if pf['id']==sm['product_id'][0]:
                    prd_id = pf['id']
                    prd_code = pf['default_code']
                    prd_name = pf['name']
                    prd_avb_st = pf['qty_available']
                    prd_vrt_st = pf['virtual_available']
                    prd_min = sm['product_min_qty']
                    prd_can_prd_max = can_prd_global_IMP(prd_id,request)
                    sales = result_dic_sales[request.user.username].get(prd_id,0)
                    productions = result_dic_Productions[request.user.username].get(prd_id,0)
                    stock_init = Get_Stock_Init(request,pf['default_code'])
                    prd_couvrt = 0
                    print(pf['default_code'],date_pr.year,date_pr.month,get_prevesion_quantity(request,pf['default_code'],date_pr.year,date_pr.month))
                    
                    if prd_min==0:
                        prd_couvrt = 0
                    else:
                        prd_couvrt = prd_vrt_st/prd_min

                    if prd_vrt_st<=0:
                        prd_couvrt = 0

                    

                    prd_ecart = prd_min-stock_init
                    combined_item = {
                                    'id':prd_id,
                                    'default_code':prd_code,
                                    'name':prd_name,
                                    'qty_available':prd_avb_st,
                                    'virtual_available':prd_vrt_st,
                                    'product_min_qty':prd_min,
                                    'ecar':prd_ecart,
                                    'couvert':prd_couvrt,
                                    'prd_max':prd_can_prd_max,
                                    'sales':sales,
                                    'productions':productions,
                                    'remaining_prod':abs(prd_ecart)-productions,
                                    'stock_init':stock_init,
                                }
                    PF_sf.append(combined_item)
    else:
        for pf in Articles_PF_dic[request.user.username]:            
                prd_id = pf['id']
                prd_code = pf['default_code']
                prd_name = pf['name']
                prd_avb_st = pf['qty_available']
                prd_vrt_st = pf['virtual_available']
                prd_min = get_prevesion_quantity(request,pf['default_code'],date_pr.year,date_pr.month)
                print(pf['default_code'],prevesion_moyenne(pf['default_code'],date_pr.year))
                prd_can_prd_max = can_prd_global_IMP(prd_id,request)
                sales = result_dic_sales[request.user.username].get(prd_id,0)
                productions = result_dic_Productions[request.user.username].get(prd_id,0)
                stock_init = Get_Stock_Init(request,pf['default_code'])
                prd_ecart = prd_min-stock_init
                prd_couvrt = 0
                #print(pf['default_code'],date_pr.year,date_pr.month,get_prevesion_quantity(request,pf['default_code'],date_pr.year,date_pr.month))
                
                
                if prd_min==0:
                    prd_couvrt = 0
                else:
                    prd_couvrt = prd_vrt_st/prd_min

                if prd_vrt_st<=0:
                    prd_couvrt = 0

                
                combined_item = {
                                    'id':prd_id,
                                    'default_code':prd_code,
                                    'name':prd_name,
                                    'qty_available':prd_avb_st,
                                    'virtual_available':prd_vrt_st,
                                    'product_min_qty':prd_min,
                                    'ecar':prd_ecart,
                                    'couvert':prd_couvrt,
                                    'prd_max':prd_can_prd_max,
                                    'sales':sales,
                                    'productions':productions,
                                    'remaining_prod':abs(prd_ecart)-productions,
                                    'stock_init':stock_init,
                                }
                PF_sf.append(combined_item)

    PF_SM_dic[request.user.username] =PF_sf
    global result_prd_dic
    result_prd_dic[request.user.username] =PF_sf
    if form.is_valid():
        if form.cleaned_data['default_code']:            
            PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if form.cleaned_data['default_code'].lower() in art['default_code'].lower() or form.cleaned_data['default_code'].lower() in art['name'].lower()] 
        if form.cleaned_data['chiffre']:
            if form.cleaned_data['regle']:
                if form.cleaned_data['regle'] == 'egal': 
                    PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if art[form.cleaned_data['chiffre']] == form.cleaned_data['val']]
                elif form.cleaned_data['regle'] =='notegal': 
                    PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if art[form.cleaned_data['chiffre']] != form.cleaned_data['val']] 
                elif form.cleaned_data['regle'] =='sup': 
                    PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if art[form.cleaned_data['chiffre']] > form.cleaned_data['val']] 
                elif form.cleaned_data['regle'] =='inf': 
                    PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if art[form.cleaned_data['chiffre']] < form.cleaned_data['val']]
                elif form.cleaned_data['regle'] =='supegal': 
                    PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if art[form.cleaned_data['chiffre']] >= form.cleaned_data['val']] 
                else:
                    PF_SM_dic[request.user.username] = [art for art in PF_SM_dic[request.user.username] if art[form.cleaned_data['chiffre']] <= form.cleaned_data['val']]
                    
                       
    PF_SM_dic[request.user.username] = sorted(PF_SM_dic[request.user.username],key=lambda art: art["default_code"])

    #Save_Stock_Prevu(request)
    context = {
        'produits' : PF_SM_dic[request.user.username],
        'nom':'Produits de la boutique',
        'form': form,
        'name_erp':request.session.get('current_company_id', ''),
        'nbr_result':len(PF_SM_dic[request.user.username]),
        'access':get_access(request.user.username),
        }
    
    return render(request,'index.html',context)


def Init_PRG(request):

    name_erp = username_erp_name(request)
    form = ArticleFilterForm(request.GET or None)
    #global result

    global PF_SM_dic
    PF_sf = []
    date_pr = date.today()
    par = get_paramettre(request.user.username)
    if par.prevision_ERP:
        for pf in Articles_PF_dic[request.user.username]:
            for sm in Stock_min_dic[request.user.username]:
                if pf['id']==sm['product_id'][0]:
                    prd_id = pf['id']
                    prd_code = pf['default_code']
                    prd_name = pf['name']
                    prd_avb_st = pf['qty_available']
                    prd_vrt_st = pf['virtual_available']
                    prd_min = sm['product_min_qty']
                    prd_min_avrg = sm['product_min_qty']
                    combined_item = {
                                    'id':prd_id,
                                    'default_code':prd_code,
                                    'name':prd_name,
                                    'qty_available':prd_avb_st,
                                    'virtual_available':prd_vrt_st,
                                    'product_min_qty':prd_min,
                                    'prd_min_avrg':prd_min_avrg,
                                }
                    PF_sf.append(combined_item)
    else:
        for pf in Articles_PF_dic[request.user.username]:            
                prd_id = pf['id']
                prd_code = pf['default_code']
                prd_name = pf['name']
                prd_avb_st = pf['qty_available']
                prd_vrt_st = pf['virtual_available']
                prd_min = get_prevesion_quantity(request,pf['default_code'],date_pr.year,date_pr.month)
                prd_min_avrg = prevesion_moyenne(pf['default_code'],date_pr.year)
                
                combined_item = {
                                    'id':prd_id,
                                    'default_code':prd_code,
                                    'name':prd_name,
                                    'qty_available':prd_avb_st,
                                    'virtual_available':prd_vrt_st,
                                    'product_min_qty':prd_min,
                                    'prd_min_avrg':prd_min_avrg,
                                }
                PF_sf.append(combined_item)

    global result_prd_dic
    result_prd_dic[request.user.username] =PF_sf
    

def can_prd_global_IMP(product_id,request):

    global Boms_dic,cat_imporation_id

    #selected_boms = [bom for bom in Boms_dic[request.user.username] if bom['product_id'][0] ==product_id ]

    liste_boms = [bom for bom in Boms_dic[request.user.username] if bom['product_id'][0] ==product_id ]
    #print("selected bom ",liste_boms)


    list_prd_max = []
    if len(liste_boms)==0:
        return 0
    
    for bom in liste_boms:
        cp = can_product_IMP(bom['id'],request.session.get('cat_imp_id', ''),request)
        
        list_prd_max.append(cp)
    
    if max(list_prd_max)<=0:
        return 0
    else:
        return max(list_prd_max)
    
def can_product_IMP(bom_id,cat_imp,request):
    
    elem = []
    global Boms_dic,Bom_Lines_dic
    bom = [bm for bm in Boms_dic[request.user.username] if bom_id == bm['id']]
    
     
    
    bomlines_prd = [bl['bom_lines'] for bl in Bom_Lines_dic[request.user.username] if bom_id == bl['bom_id']][0]

    
    for bom_line_prd in bomlines_prd:
        cpt_id_prd = bom_line_prd['product_id'][0]
        if get_product(cpt_id_prd,request):
            cpt_qty_prd = get_product(cpt_id_prd,request)[0]['virtual_available']
        else:
            cpt_qty_prd = 0
        qty = cpt_qty_prd*bom[0]['product_qty']/bom_line_prd['product_qty']
        if get_product(cpt_id_prd,request):
            cate_ids = get_product(cpt_id_prd,request)[0]['categ_id']
        else:
            cate_ids=[]
        if len(cate_ids)>0 and cate_ids[0]==cat_imp:
            elem.append(int(qty))

    
    float_list = [float(i) for i in elem]
    if len(float_list)==0:
        return 0
    return min(float_list)




def get_product(id_prd,request):
    global Articles_MP_dic
    art = [art for art in Articles_MP_dic[request.user.username] if id_prd == art['id']]
    return art

def get_product_by_code(id_prd,request):
    global Articles_MP_dic_imp
    art = [art for art in Articles_MP_dic_imp[request.user.username] if id_prd == art['default_code']]
    return art

def can_product_IMP_Uniq(bom_id,cat_imp,request):
    
    elem = []
    global Boms_dic,Bom_Lines_dic
    
    bom = [bm for bm in Boms_dic[request.user.username] if bom_id == bm['id']]
   
    
    bomlines_prd = [bl['bom_lines'] for bl in Bom_Lines_dic[request.user.username] if bom_id == bl['bom_id']][0]
    

    bomlines_prd_diff = [bl['bom_lines'] for bl in Bom_Lines_dic[request.user.username] if bom_id != bl['bom_id']]
    
    article_prd_diff = []

    for bl in bomlines_prd_diff:
        #print('bom_lines',bl)
        for b in bl:
            #print('aticle',b['product_id'][0])
            article_prd_diff.append(b['product_id'][0])
    

    #article_prd_diff = list(set(article_prd_diff))
    #print(bomlines_prd_diff)
    
    for bom_line_prd in bomlines_prd:
        
        cpt_id_prd = bom_line_prd['product_id'][0]

        existe = [x for x in article_prd_diff if cpt_id_prd == x]
        
        cpt_qty_prd = get_product(cpt_id_prd,request)[0]['virtual_available']
        qty = cpt_qty_prd*bom[0]['product_qty']/bom_line_prd['product_qty']
        cate_ids = get_product(cpt_id_prd)[0]['categ_id']
        if len(existe)!=0:
            print('existe',get_product(cpt_id_prd,request)[0]['default_code'])
        else:
            print('not existe',get_product(cpt_id_prd,request)[0]['default_code'])

        if  len(existe)==0 and cate_ids == cat_imp:
            elem.append(int(qty))

    
    float_list = [float(i) for i in elem]
    if len(float_list) == 0:
        return 0
    return min(float_list)


def can_product_global(bom_id,request):
    
    elem = []
    global Boms_dic,Bom_Lines_dic
    bom = [bm for bm in Boms_dic[request.user.username] if bom_id == bm['id']]
     
    bomlines_prd = [bl['bom_lines'] for bl in Bom_Lines_dic[request.user.username] if bom_id == bl['bom_id']][0]
    for bom_line_prd in bomlines_prd:
        cpt_id_prd = bom_line_prd['product_id'][0]
        if get_product(cpt_id_prd,request):
            cpt_qty_prd = get_product(cpt_id_prd,request)[0]['virtual_available']
        else:
            cpt_qty_prd = 0

        qty = cpt_qty_prd*bom[0]['product_qty']/bom_line_prd['product_qty']
        elem.append(int(qty))
    
    float_list = [float(i) for i in elem]
    if len(float_list)==0:
        return 0
    return min(float_list)


def pdp(request):

    form = ArticleFilterForm(request.GET or None)
    selected_prds =[]
    selected_boms =[]
    selected_id =[]
    global PF_SM_dic,Boms_dic
    if request.method == "POST":
        
        #selected_id = request.POST.get('articles')
        request.session['selected_id'] = request.POST.get('articles')
    #print(request.session.get('selected_id', ''))
    selected_prds = [art for art in PF_SM_dic[request.user.username] if str(art['id']) in request.session.get('selected_id', '')] 
    selected_boms = [bom for bom in Boms_dic[request.user.username] if str(bom['product_id'][0]) in request.session.get('selected_id', '')]
    
    
    #print('PFG',PF_SM_dic[request.user.username])
    #print('PFS',selected_prds)
    #print('BOMS',selected_boms)
    gamme =0
    gamme_uniq =0
    list_boms = []

    if form.is_valid():        
        if form.cleaned_data['gamme']:
            gamme = 1   
            for bom in selected_boms:

                combined_item = {**bom,}
                
                cp = can_product_IMP(bom['id'],request.session.get('cat_imp_id', ''),request)
                combined_item['can_prd']=cp
                
                list_boms.append(combined_item)
        else: 
            if form.cleaned_data['gamme_uniq']: 
                gamme_uniq = 1          
                for bom in selected_boms:
                    combined_item = {**bom,}
                    cp = can_product_IMP_Uniq(bom['id'],request.session.get('cat_imp_id', ''),request)
                    combined_item['can_prd']=cp
                    
                    list_boms.append(combined_item)
            else:
                for bom in selected_boms:
                    combined_item = {**bom,}
                    cp = can_product_global(bom['id'],request)
                    combined_item['can_prd']=cp
                    
                    
                    list_boms.append(combined_item)

        
    else:
        #print('global')
        for bom in selected_boms:
            combined_item = {**bom,}
            cp = can_product_global(bom['id'],request)
            
            combined_item['can_prd']=cp
            
            list_boms.append(combined_item)
    can_prd =0
    cant_prd =0
    default_code =''
    pdp_list = []

    

    for sp in selected_prds:
        for bm in list_boms:
             if sp['id']==bm['product_id'][0]:
                combined_item = {**sp,**bm,}
                #print('car prd',bm['can_prd'],' ecar prd',sp['ecar'])
                combined_item['ecart_pdp']=bm['can_prd']-abs(sp['ecar'])
                combined_item['prd_id']=sp['id']
                combined_item['bom_name']=bm['name']
                combined_item['prd_name']=sp['name']
                global uid
           
                combined_item['opr_typr']=get_opr_type(request.session.get('uid', ''),request.session.get('current_company_id', ''))
                pdp_list.append(combined_item)

    #print('pdp list=',pdp_list)
    
    if form.is_valid():
        if form.cleaned_data['default_code']:
            default_code = form.cleaned_data['default_code']
            pdp_list = [art for art in pdp_list if form.cleaned_data['default_code'].lower() in art['default_code'].lower() or form.cleaned_data['default_code'].lower() in art['name'].lower()] 
        if form.cleaned_data['can_prd']:
            can_prd =1
            pdp_list = [art for art in pdp_list if art['can_prd']>0] 
        if form.cleaned_data['cant_prd']:
            cant_prd =1
            pdp_list = [art for art in pdp_list if art['can_prd']<=0] 
        
    pdp_list.sort(key=lambda ap:(ap['default_code'],ap['code']))

    pdp_list_dic_global[request.user.username]=pdp_list

    data = {
       'article_pdp':pdp_list_dic_global[request.user.username],
       'gamme':gamme,
       'gamme_uniq':gamme_uniq,
       'can_prd':can_prd,
       'cant_prd':cant_prd,
       'default_code':default_code,
       'nbr_result':len(pdp_list_dic_global[request.user.username]),
       'access':get_access(request.user.username),
    } 

   
    
    
    
    
    
    
    return render(request, 'pdp.html', data)

def get_bom_prd_qty(id_bom,request):
    global Boms_dic

    result = [bm for bm in Boms_dic[request.user.username] if bm['id'] == id_bom]
    return result[0]['product_qty']


def get_bom_lines(id_bom,request):
    par = get_paramettre(request.user.username)
    common = xmlrpc.client.ServerProxy(f'{par.link_db}/xmlrpc/2/common')
    models = xmlrpc.client.ServerProxy(f'{par.link_db}/xmlrpc/2/object')

    uid = common.authenticate(
                            par.database, 
                            request.user.username, 
                            request.session.get('pw', ''),
                            {})
    fields6 = ['product_id', 'product_qty']

    bom_data = models.execute_kw(par.database,
                                uid,
                                request.session.get('pw', ''),
                                'mrp.bom',
                                'read',
                                [id_bom],
                                {'fields': ['bom_line_ids']})
    
    bom_line_ids = bom_data['bom_line_ids'] if bom_data else []
    bom_lines = models.execute_kw(par.database, uid, request.session.get('pw', ''), 'mrp.bom.line', 'read', [bom_line_ids], {'fields': fields6})
    return bom_lines

def appros(request):
   
    appros_gl = []
    
    if request.method == "POST":
        request.session['pdp_items'] = json.loads(request.POST.get('my_list'))
        #print(request.session.get('pdp_items', ''))

    for item in request.session.get('pdp_items', ''):
        
        bom_qty= get_bom_prd_qty(int(item['id_bom']),request)
        for line in get_bom_lines(int(item['id_bom']),request):            
            product_id = line['product_id'][0]  # Product name
            product_qty = line['product_qty']*float(item['qty'])/bom_qty

            x1 = {'product_id':product_id,'product_qty':product_qty}
            appros_gl.append(x1)

    #print(appros_gl)

    
    cmp_data_sum = {}

    for component in appros_gl:
        cmp_id = component['product_id']
        cmp_qty = component['product_qty']
        # Si le cmp_id existe déjà, ajouter à la quantité existante
        if cmp_id in cmp_data_sum:
            cmp_data_sum[cmp_id]['cmp_qty'] += cmp_qty
        else:
            cmp_data_sum[cmp_id] = {
                'cmp_id': cmp_id,
                'cmp_qty': cmp_qty
            }

    # Convertir le dictionnaire en liste d'objets (dictionnaires)
    result_list_appro = list(cmp_data_sum.values())
    result_list_appros = []
    for rst in result_list_appro:
        app = {
                'code': get_product(rst['cmp_id'],request)[0]['default_code'],
                'name': get_product(rst['cmp_id'],request)[0]['name'],
                'qty_available': get_product(rst['cmp_id'],request)[0]['qty_available'],
                'virtual_available': get_product(rst['cmp_id'],request)[0]['virtual_available'],
                'cmp_qty':rst['cmp_qty'],
                'ecar':get_product(rst['cmp_id'],request)[0]['virtual_available']- rst['cmp_qty']
            
            }

        result_list_appros.append(app)
    
    result_list_appros.sort(key=lambda ap: ap['code'])
    
    data = {
      'appros':result_list_appros,
      'nbr_result':len(result_list_appros),
      'access':get_access(request.user.username),
    }
    
    return render(request, 'appros.html', data) 


listeMP_Reserve_dic = {}
def GetArticleQtyReszervation(prd_id,request):
    global listeMP_Reserve_dic
    

    total = sum(item['qty_reserve'] for item in listeMP_Reserve_dic[request.user.username] if item['id_mp']  == prd_id)
    
    
    return total

def Addresevation(bom_id1,qtyG,request):
    #print('id bom',bom_id1,type(bom_id1))
    listeMP_Reserve=[]
    global Boms_dic
    bom = [bm for bm in Boms_dic[request.user.username] if int(bom_id1) == bm['id']]
    #print('boms',bom)
    global Bom_Lines_dic
    bomlines_prd = [bl['bom_lines'] for bl in Bom_Lines_dic[request.user.username] if int(bom_id1) == bl['bom_id']][0]
    for bom_line_prd in bomlines_prd:
        cpt_id_prd = bom_line_prd['product_id'][0]
        qty = bom_line_prd['product_qty']*float(qtyG)/bom[0]['product_qty']
        x = {'id_mp':cpt_id_prd,'qty_reserve':qty}
        listeMP_Reserve.append(x)

    listeMP_Reserve_dic[request.user.username]= listeMP_Reserve

def can_product_global_resevation(bom_id,request):
    
    elem = []
    global Boms_dic
    bom = [bm for bm in Boms_dic[request.user.username] if int(bom_id) == bm['id']]
    global Bom_Lines_dic
    bomlines_prd = [bl['bom_lines'] for bl in Bom_Lines_dic[request.user.username] if int(bom_id) == bl['bom_id']][0]
    for bom_line_prd in bomlines_prd:
        cpt_id_prd = bom_line_prd['product_id'][0]
        cpt_qty_prd = get_product(cpt_id_prd,request)[0]['virtual_available']-GetArticleQtyReszervation(cpt_id_prd,request)
        qty = cpt_qty_prd*bom[0]['product_qty']/bom_line_prd['product_qty']
        elem.append(int(qty))
    
    float_list = [float(i) for i in elem]
    if len(float_list)==0:
        return 0
    return min(float_list)


def prd_pdp_detail(request):
    
    if request.method == "POST":
        
       
        request.session['code_prd'] = request.POST.get('code_prd','')
        
        request.session['code_bom'] = request.POST.get('code_bom','')
        
        
        
    global pdp_list_dic
    
    prd_detail = [art for art in pdp_list_dic[request.user.username] if request.session.get('code_prd', '') == art['default_code'] and request.session.get('code_bom', '') == art['code']]
    

    name_prd = prd_detail[0]['prd_name']
    name_bom = prd_detail[0]['bom_name']
    can_prd = prd_detail[0]['can_prd']
    should_prd = abs(prd_detail[0]['ecar'])
    
    global Bom_Lines_dic
    bomlines_prd = [bl['bom_lines'] for bl in Bom_Lines_dic[request.user.username] if prd_detail[0]['id'] == bl['bom_id']][0]
    
    global prd_pdp_detail_list_dic
    prd_pdp_detail_list = []

    for bom_line_prd in bomlines_prd:
        cpt_id_prd = bom_line_prd['product_id'][0]
        cpt_qty_prd = get_product(cpt_id_prd,request)[0]['virtual_available']


        qty = cpt_qty_prd*prd_detail[0]['product_qty']/bom_line_prd['product_qty']
        x={
            'default_code':get_product(cpt_id_prd,request)[0]['default_code'],
            'name':get_product(cpt_id_prd,request)[0]['name'],
            'qty_available':get_product(cpt_id_prd,request)[0]['qty_available'],
            'virtual_available':get_product(cpt_id_prd,request)[0]['virtual_available'],
            'sale_ok':get_product(cpt_id_prd,request)[0]['sale_ok'],
            'purchase_ok':get_product(cpt_id_prd,request)[0]['purchase_ok'],
            'categ_id':get_product(cpt_id_prd,request)[0]['categ_id'],
            'qty':int(qty)

            }            
        prd_pdp_detail_list.append(x)
    prd_pdp_detail_list_dic[request.user.username] = prd_pdp_detail_list
    #print(elem)
    
    
    

    form = ArticleFilterForm(request.GET or None)
    game = 0
    loc_prd = 0
    prduc_prd = 0
    Stock_min_filtre1 = []
    if form.is_valid():
        
        cat_imporation_id = request.session.get('cat_imp_id', '')
        if form.cleaned_data['gamme']:
            game = 1
            Stock_min_filtre1 += [prd for prd in prd_pdp_detail_list_dic[request.user.username] if prd['categ_id'][0] == cat_imporation_id]
        if form.cleaned_data['loc_prd']:
            loc_prd = 1
            Stock_min_filtre1 += [prd for prd in prd_pdp_detail_list_dic[request.user.username] if prd['categ_id'][0] != cat_imporation_id and prd['purchase_ok']==True]
        if form.cleaned_data['prduc_prd']:
            prduc_prd = 1
            Stock_min_filtre1 += [prd for prd in prd_pdp_detail_list_dic[request.user.username] if prd['sale_ok']==False and prd['purchase_ok']==False]
        
    else:
         Stock_min_filtre1 = prd_pdp_detail_list_dic[request.user.username]
    
    Stock_min_filtre1.sort(key=lambda ap: ap['qty'])

    data = {
                'detail':Stock_min_filtre1,
                'article_pdp':request.session.get('code_prd', ''),
                'name_prd':name_prd,
                'boms':name_bom,
                'can_prd':can_prd,
                'gamme':game,
                'loc_prd':loc_prd,
                'prduc_prd':prduc_prd,
                'should_prd':should_prd,
                'access':get_access(request.user.username),
            }
   

    return render(request, 'prd_pdp_detail.html', data)


def pdp_semulat(request):
    
    global listeMP_Reserve_dic
    listeMP_Reserve_dic[request.user.username] = []
    productPF_SEMUL = []
    
    if request.method == "POST":
        
        request.session['pdp_simulet_items'] = json.loads(request.POST.get('my_list'))
        #print('liste complet',request.session.get('pdp_simulet_items', ''))

    



    
    #print(GetArticleQtyReszervation(22829))
    

    for rpf in request.session.get('pdp_simulet_items', ''):
        qty_simulation = can_product_global_resevation(rpf['id_bom'],request)
        qty_planifie = rpf['qty']
        qty_resulat = qty_planifie
        if qty_simulation < float(qty_planifie):
            qty_resulat = qty_simulation
        
        prdpfline = {
            'id_prd':rpf['id_prd'],
            'id_bom':rpf['id_bom'],
            'qty_planifie':float(qty_planifie),
            'qty_resulat':float(qty_resulat),
        }

        #prdpfline = {'id_prd':rpf['id_prd'],'id_bom':rpf['id_bom'],'qty':can_product_global_resevation(rpf['id_bom'])}
        productPF_SEMUL.append(prdpfline)
        Addresevation(prdpfline['id_bom'],prdpfline['qty_resulat'],request)
    

    #print('hhhh',productPF_SEMUL)

    
    global  product_couvetutre  
    
    productPF_SEMUL_PDP=[]
    #print('len',product_couvetutre)
    for prd_simul in productPF_SEMUL:
        for pc in PF_SM_dic[request.user.username]:
            if int(prd_simul['id_prd'])==pc['id']:
                bom = get_bom(int(prd_simul['id_bom']),request)
                global uid
                line = {
                    'id':pc['id'],
                    'default_code':pc['default_code'],
                    'prd_name':pc['name'],
                    'qty_available':pc['qty_available'],
                    'virtual_available':pc['virtual_available'],
                    'product_min_qty':pc['product_min_qty'],
                    'ecar':pc['ecar'],
                    'qty_planifie':prd_simul['qty_planifie'],
                    'qty_resulat':prd_simul['qty_resulat'],
                    'bom_id':bom['id'],
                    'bom_code':bom['code'],
                    'bom_name':bom['name'],
                    'opr_typr':get_opr_type(request.session.get('uid', ''),request.session.get('current_company_id', ''))

                }
                #print('line',line)
                
                productPF_SEMUL_PDP.append(line)
     

       
    productPF_SEMUL_PDP.sort(key=lambda ap:(ap['default_code'],ap['bom_code']))
    data = {
        'products':productPF_SEMUL_PDP,
        'access':get_access(request.user.username),
        
    } 
    
    return render(request, 'pdp_semulat.html', data)



def production(request):
    form = ArticleFilterForm(request.GET or None)
    prds_prd = []
    global result_prd_dic
    gamme =0
    if form.is_valid():        
        if form.cleaned_data['gamme']:
            gamme = 1
            for art_prd in  result_prd_dic[request.user.username]:
                for bom_prd in Boms_dic[request.user.username]:
                    if art_prd['id']==bom_prd['product_id'][0]:
                        
                        cat_imporation_id = request.session.get('cat_imp_id', '')
                        #print('cat imp',cat_imporation_id)
                        x= {
                                'code':art_prd['default_code'],
                                'name':art_prd['name'],
                                'stock_v':art_prd['virtual_available'],
                                'ecart':art_prd['virtual_available']-art_prd['product_min_qty'],
                                'bom':bom_prd['code'],
                                'qty':can_product_IMP(bom_prd['id'],cat_imporation_id,request)}    
                        prds_prd.append(x)
        else:
            for art_prd in  result_prd_dic[request.user.username]:
                for bom_prd in Boms_dic[request.user.username]:
                    if art_prd['id']==bom_prd['product_id'][0]:
                        x= {
                            'code':art_prd['default_code'],
                            'name':art_prd['name'],
                            'stock_v':art_prd['virtual_available'],
                            'ecart':art_prd['virtual_available']-art_prd['product_min_qty'],
                            'bom':bom_prd['code'],
                            'qty':can_product_global(bom_prd['id'],request)}    
                        prds_prd.append(x)
    else:
        
        for art_prd in  result_prd_dic[request.user.username]:
            for bom_prd in Boms_dic[request.user.username]:
                if art_prd['id']==bom_prd['product_id'][0]:
                    x= {
                        'code':art_prd['default_code'],
                        'name':art_prd['name'],
                        'stock_v':art_prd['virtual_available'],
                        'ecart':art_prd['virtual_available']-art_prd['product_min_qty'],
                        'bom':bom_prd['code'],
                        'qty':can_product_global(bom_prd['id'],request)}    
                    prds_prd.append(x)
    prd_shearch = ''

    if form.is_valid():        
        if form.cleaned_data['default_code']:
            prd_shearch = form.cleaned_data['default_code']
            prds_prd = [l for l in prds_prd if form.cleaned_data['default_code'].lower() in l['code'].lower() or  form.cleaned_data['default_code'].lower() in l['name'].lower()]

    prds_prd.sort(key=lambda ap: (ap['code'],ap['bom']))            
    
    data = {
        'products' : prds_prd,
        'prd_shearch' :prd_shearch,
        'gamme' :gamme,
        'nbr_result':len(prds_prd),
        'access':get_access(request.user.username),
        } 
   
    return render(request, 'can_prd.html', data)

def Cbn(request,*args,**kwargs):

    global result_prd_dic
    
    result_prd_filtre = []
    default_code =''
    form = ArticleFilterForm(request.GET or None)
    if form.is_valid():
        if form.cleaned_data['default_code']:
            default_code = form.cleaned_data['default_code']
            result_prd_filtre = [art  for art in result_prd_dic[request.user.username] if form.cleaned_data['default_code'].lower() in art['default_code'].lower() or form.cleaned_data['default_code'].lower() in art['name'].lower() ]
        else:
            result_prd_filtre = result_prd_dic[request.user.username]
    else:
        result_prd_filtre = result_prd_dic[request.user.username]

    result_prd_filtre.sort(key=lambda ap: ap['default_code'])

    result_prd_filtre_dic[request.user.username] = result_prd_filtre

    global Boms_dic
    #print(Boms)
    context = {
        'products' : result_prd_filtre_dic[request.user.username],
        'nom':default_code,
        'boms':Boms_dic[request.user.username],
        'nbr_result':len(result_prd_filtre_dic[request.user.username]),
        'access':get_access(request.user.username),
        }
    
    
    return render(request,'cbn.html',context)




result_simulation_planification_global = {}







def Get_Month_Digit(month):
    switch = {
        'January':1,
        'February':2,
        'March':3,
        'April':4,
        'May':5,
        'June':6,
        'July':7,
        'August':8,
        'September':9,
        'October':10,
        'November':11,
        'December':12
    }
    return  switch.get(month, 0)

Transit_time_G = {}
Month_global = {}
Month_title_global = {}

Needs_global = {}

Plan_charement_G = {}
Plan_charement = []

Month_PA = []
Month_PA_Title = []
Month_PA_Title_Show = []

Month_PA_G = {}
Month_PA_Title_G = {}
Month_PA_Title_Show_G = {}
Month_ORG = {}
def Simulation_Chargement_calcule(request):

    print('jours resant',Get_Days_Remaining())
    selected_id_sp = []
    Nbr_month = 0
    Transit_time = 0
    if request.method == "POST":
        selected_id_json = request.POST.get('articles')
        selected_id_sp = json.loads(selected_id_json)
        Nbr_month_str = request.POST.get('Nbr_month')  # on récupère en tant que str
        print('Nbr_month', Nbr_month_str)

        if Nbr_month_str and Nbr_month_str.strip().isdigit():
            Nbr_month = int(Nbr_month_str)
        else:
            Nbr_month = 1  # ou 0, selon ton besoin

        Transit_time_str = request.POST.get('Transit_time')  # on récupère en tant que str
        print('Transit_time', Transit_time_str)

        if Transit_time_str and Transit_time_str.strip().isdigit():
            Transit_time = int(Transit_time_str)
            Transit_time_G[request.user.username] = Transit_time
        else:
            Transit_time = 90  # ou 0, selon ton besoin

    print('Transit_time g', Transit_time_G[request.user.username])
    Nbr_months = Nbr_month - 1

    global result_prd_filtre_dic
    global Bom_Lines
    result_simulation_planification = []
    if(Nbr_months==0):
        print('mois encours')
        for rp in result_prd_filtre_dic[request.user.username]:
            for l in selected_id_sp :
                if rp['default_code'] == l[0]:
                    rp['bom_id'] = float(l[1])
                    rp['virtu_qty'] = float(l[2])
                    rp['prevu_qty'] = float(l[3])
        stock_min = []
        Stock_mins = []
        for art_prd in  result_prd_filtre_dic[request.user.username]:
            boms_prd = [bom for bom in Boms_dic[request.user.username] if bom['id'] == art_prd['bom_id']]
            #print(boms_prd)
            boms_cpts = []
            for bom_prd in boms_prd:
                bomlines_prd = [bl['bom_lines'] for bl in Bom_Lines_dic[request.user.username] if bom_prd['id'] == bl['bom_id']][0]
                #bomlines_prd = get_bom_lines(bom_prd['id'])
                for bom_line_prd in bomlines_prd:
                    item = {'id':bom_line_prd['product_id'][0],'qty':bom_line_prd['product_qty'],'bom_qty':bom_prd['product_qty']}
                    boms_cpts.append(item)
        
            boms_cpts_clean = list({obj['id']: obj for obj in boms_cpts}.values())
            
            for cpt in boms_cpts_clean:
                
                virtu_qty = cpt['qty']*art_prd['virtu_qty']/cpt['bom_qty']
                prevu_qty = cpt['qty']*art_prd['prevu_qty']/cpt['bom_qty']
                prd = get_product(cpt['id'],request)[0]
                
                
                
                composant = {'code':prd['default_code'],'name':prd['name'],'virtu_qty':virtu_qty,'prevu_qty':prevu_qty,'sale_ok':prd['sale_ok'],'purchase_ok':prd['purchase_ok'],'categ_id':prd['categ_id'],'virtual_available':prd['virtual_available']}
                stock_min.append(composant)
                
        
        cmp_data_sum = {}

        for component in stock_min:
            cmp_id = component['code']
            virtu_qty = component['virtu_qty']
            prevu_qty = component['prevu_qty']
            
            
            # Si le cmp_id existe déjà, ajouter à la quantité existante
            if cmp_id in cmp_data_sum:
                cmp_data_sum[cmp_id]['virtu_qty'] += virtu_qty
                cmp_data_sum[cmp_id]['prevu_qty'] += prevu_qty
                
            else:
                # Sinon, initialiser les informations pour ce cmp_id
                cmp_data_sum[cmp_id] = {
                    'code': component['code'],
                    'name': component['name'],
                    'categ_id': component['categ_id'],
                    'virtual_available': component['virtual_available'],
                    'virtu_qty': virtu_qty,
                    'prevu_qty': prevu_qty,
                    
                # 'ecart': component['virtual_available']+virtu_qty+chrg_qty-prevu_qty
                }

            # Convertir le dictionnaire en liste d'objets (dictionnaires)
            Stock_mins = list(cmp_data_sum.values())
        

        cat_imporation_id = request.session.get('cat_imp_id', '')
        Stock_min_filtre = []
        Stock_min_filtre = [prd for prd in Stock_mins if prd['categ_id'][0] == cat_imporation_id]
        today = date.today()
        month_name = today.strftime("%B")
        print('i:1','month',month_name)
        for p in Stock_min_filtre:
            rsp = {
                'code':p['code'],
                'nom':p['name'],
                'inhand':Get_InHandByCode(request,p['code']),
                'prevu_qty':p['prevu_qty'],
                'qty':p['virtual_available']+p['virtu_qty']+ Get_ChargementByCode(request,p['code'],0,Transit_time)-p['prevu_qty']/22*Get_Days_Remaining(),
                'month':month_name
            }
            result_simulation_planification.append(rsp)
        result_simulation_planification_global[request.user.username] = result_simulation_planification

    else:

        print('periode')
        for rp in result_prd_filtre_dic[request.user.username]:
            for l in selected_id_sp :
                if rp['default_code'] == l[0]:
                    rp['bom_id'] = float(l[1])
                    rp['virtu_qty'] = float(l[2])
                    rp['prevu_qty'] = float(l[3])

        for i in range(0, Nbr_month):
            if i ==0:
                print('itération 1')
                stock_min = []
                Stock_mins = []
                for art_prd in  result_prd_filtre_dic[request.user.username]:
                    boms_prd = [bom for bom in Boms_dic[request.user.username] if bom['id'] == art_prd['bom_id']]
                    #print(boms_prd)
                    boms_cpts = []
                    for bom_prd in boms_prd:
                        bomlines_prd = [bl['bom_lines'] for bl in Bom_Lines_dic[request.user.username] if bom_prd['id'] == bl['bom_id']][0]
                        #bomlines_prd = get_bom_lines(bom_prd['id'])
                        for bom_line_prd in bomlines_prd:
                            item = {'id':bom_line_prd['product_id'][0],'qty':bom_line_prd['product_qty'],'bom_qty':bom_prd['product_qty']}
                            boms_cpts.append(item)
                
                    boms_cpts_clean = list({obj['id']: obj for obj in boms_cpts}.values())
                    
                    for cpt in boms_cpts_clean:
                        virtu_qty = cpt['qty']*art_prd['virtu_qty']/cpt['bom_qty']
                        prevu_qty = cpt['qty']*art_prd['prevu_qty']/cpt['bom_qty']
                        prd = get_product(cpt['id'],request)[0]
                        
                        
                        composant = {'code':prd['default_code'],'name':prd['name'],'virtu_qty':virtu_qty,'prevu_qty':prevu_qty,'sale_ok':prd['sale_ok'],'purchase_ok':prd['purchase_ok'],'categ_id':prd['categ_id'],'virtual_available':prd['virtual_available']}
                        stock_min.append(composant)
                
                cmp_data_sum = {}

                for component in stock_min:
                    cmp_id = component['code']
                    virtu_qty = component['virtu_qty']
                    prevu_qty = component['prevu_qty']
                    
                    
                    # Si le cmp_id existe déjà, ajouter à la quantité existante
                    if cmp_id in cmp_data_sum:
                        cmp_data_sum[cmp_id]['virtu_qty'] += virtu_qty
                        cmp_data_sum[cmp_id]['prevu_qty'] += prevu_qty
                        
                    else:
                        # Sinon, initialiser les informations pour ce cmp_id
                        cmp_data_sum[cmp_id] = {
                            'code': component['code'],
                            'name': component['name'],
                            'categ_id': component['categ_id'],
                            'virtual_available': component['virtual_available'],
                            'virtu_qty': virtu_qty,
                            'prevu_qty': prevu_qty,
                            
                        
                        }

                    # Convertir le dictionnaire en liste d'objets (dictionnaires)
                    Stock_mins = list(cmp_data_sum.values())
                

                cat_imporation_id = request.session.get('cat_imp_id', '')
                Stock_min_filtre = []
                Stock_min_filtre = [prd for prd in Stock_mins if prd['categ_id'][0] == cat_imporation_id]
                
                today = date.today()
                month_name = today.strftime("%B")
                print('i:0','month',month_name)

                for p in Stock_min_filtre:
                    rsp = {
                        'code':p['code'],
                        'nom':p['name'],
                        'inhand':Get_InHandByCode(request,p['code']),
                        'prevu_qty':p['prevu_qty'],
                        'qty':p['virtual_available']+p['virtu_qty']+ Get_ChargementByCode(request,p['code'],0,Transit_time)-p['prevu_qty']/22*Get_Days_Remaining(),
                        'month':month_name
                    }
                    result_simulation_planification.append(rsp)
                result_simulation_planification_global[request.user.username] = result_simulation_planification
                    
            else:
                print('itération ',i+1)
                stock_min = []
                Stock_mins = []
                for art_prd in  result_prd_filtre_dic[request.user.username]:
                    boms_prd = [bom for bom in Boms_dic[request.user.username] if bom['id'] == art_prd['bom_id']]
                    #print(boms_prd)
                    boms_cpts = []
                    for bom_prd in boms_prd:
                        bomlines_prd = [bl['bom_lines'] for bl in Bom_Lines_dic[request.user.username] if bom_prd['id'] == bl['bom_id']][0]
                        #bomlines_prd = get_bom_lines(bom_prd['id'])
                        for bom_line_prd in bomlines_prd:
                            item = {'id':bom_line_prd['product_id'][0],'qty':bom_line_prd['product_qty'],'bom_qty':bom_prd['product_qty']}
                            boms_cpts.append(item)
                
                    boms_cpts_clean = list({obj['id']: obj for obj in boms_cpts}.values())
                    
                    for cpt in boms_cpts_clean:
                        virtu_qty = 0
                        prevu_qty = 0
                        prd = get_product(cpt['id'],request)[0]
                        
                        
                        composant = {'code':prd['default_code'],'name':prd['name'],'virtu_qty':virtu_qty,'prevu_qty':prevu_qty,'sale_ok':prd['sale_ok'],'purchase_ok':prd['purchase_ok'],'categ_id':prd['categ_id'],'virtual_available':prd['virtual_available']}
                        stock_min.append(composant)
                
                cmp_data_sum = {}

                for component in stock_min:
                    cmp_id = component['code']
                    virtu_qty = component['virtu_qty']
                    prevu_qty = component['prevu_qty']
                    
                    
                    # Si le cmp_id existe déjà, ajouter à la quantité existante
                    if cmp_id in cmp_data_sum:
                        cmp_data_sum[cmp_id]['virtu_qty'] += virtu_qty
                        cmp_data_sum[cmp_id]['prevu_qty'] += prevu_qty
                        
                    else:
                        # Sinon, initialiser les informations pour ce cmp_id
                        cmp_data_sum[cmp_id] = {
                            'code': component['code'],
                            'name': component['name'],
                            'categ_id': component['categ_id'],
                            'virtual_available': component['virtual_available'],
                            'virtu_qty': virtu_qty,
                            'prevu_qty': prevu_qty,
                           
                        
                        }

                    # Convertir le dictionnaire en liste d'objets (dictionnaires)
                    Stock_mins = list(cmp_data_sum.values())
                

                cat_imporation_id = request.session.get('cat_imp_id', '')
                Stock_min_filtre = []
                Stock_min_filtre = [prd for prd in Stock_mins if prd['categ_id'][0] == cat_imporation_id]
                today = date.today()
                privious_month = today+ relativedelta(months=i-1)
                privious_month_name = privious_month.strftime("%B")

                next_month  = today + relativedelta(months=i)
                next_month_name = next_month.strftime("%B")
                print('i:',i,'previous month:',privious_month_name,'this month:',next_month_name)
                #Stock_min_filtre += [prd for prd in Stock_mins if prd['categ_id'][0] == cat_imporation_id]
                privious_month_data = [x for x in result_simulation_planification if x['month']==privious_month_name]
                
                for rsp_line in privious_month_data:
                    for p in Stock_min_filtre:
                        if rsp_line['code']== p['code']:
                            if rsp_line['qty']<0:
                                qty = Get_ChargementByCode(request,p['code'],i,Transit_time)-rsp_line['prevu_qty']
                            else:
                                qty = rsp_line['qty']+Get_ChargementByCode(request,p['code'],i,Transit_time)-rsp_line['prevu_qty']

                            #print('inhand',rsp_line['code'],Get_InHandByCode(request,rsp_line['code']))

                            rsp = {
                                'code':rsp_line['code'],
                                'nom':rsp_line['nom'],
                                'inhand':Get_InHandByCode(request,rsp_line['code']),
                                'prevu_qty':rsp_line['prevu_qty'],
                                'qty':qty,
                                'month':next_month_name
                            }
                            result_simulation_planification.append(rsp)
                        result_simulation_planification_global[request.user.username] = result_simulation_planification
        


    """ for k in result_simulation_planification:
        print('k=',k) """

    
    months = []
    seen = set()
    [months.append(m['month']) for m in result_simulation_planification_global[request.user.username] if m['month'] not in seen and not seen.add(m['month'])]
    products = []
    seen_prd = set()
    [products.append(m['code']) for m in result_simulation_planification_global[request.user.username] if m['code'] not in seen_prd and not seen_prd.add(m['code'])]
    #print('hhhhhh',products)

    
    #months = list(set([m['month'] for m in result_simulation_planification_global[request.user.username]]))

    #print(months)
    pivot = defaultdict(lambda: {month: 0 for month in months})
    for entry in result_simulation_planification_global[request.user.username]:
        article = entry['code']
        month = entry['month']
        besoin = entry['qty']
        nom = entry['nom']
        inhand = entry['inhand']
        prevu_qty = entry['prevu_qty']
        pivot[article]['nom'] = nom
        pivot[article]['inhand'] = inhand
        pivot[article]['prevu_qty'] = prevu_qty
        pivot[article][month] = besoin

    tableau = []
    for article, ligne in sorted(pivot.items()):
        row = {'article': article, 'nom': ligne['nom'], 'inhand': ligne['inhand'], 'prevu_qty': ligne['prevu_qty']}
        row.update({month: ligne[month] for month in months})
        #print('row',row)
        tableau.append(row)
    Stock_min_filtre=[]

    Needs = []
    plan_appro = []
    plan_appro_real = []
    tableau_cmd_chrg = copy.deepcopy(tableau)

    for tab in tableau_cmd_chrg:
        x = {}
        x['article'] = tab['article']
        x['nom'] = tab['nom']
        x['prevu_qty'] = tab['prevu_qty']
        x['inhand'] = tab['inhand']

        flag = 0
        for m in months:
            #x[m]= tab[m]
            #print(tab['article'],'|',tab[m])
            if tab[m] >= 0:
                x[m] = 0
            else:
                x[m] = abs(tab[m])
                
                flag += 1
        if flag > 0 :
            Needs.append(x)
            
    tableau_Needs = copy.deepcopy(Needs)


    Plan_charement = []
    Month_PA = []
    Month_PA_Title = []
    Month_PA_Title_Show = []
    
    for n in tableau_Needs:
        x = {}
        x['article'] = n['article']
        x['nom'] = n['nom']
        x['inhand'] = n['inhand']
        for m in months:
            ma_date = date(date.today().year, Get_Month_Digit(m), date.today().day)
            # vérfier si le jour de mois existe comme 31 juin n'existe pas
            ma_date = ma_date - timedelta(days=Transit_time_G[request.user.username])
            chrg = 0
            cmd = 0
            if n[m]==0:
                chrg = 0
                cmd = 0
                #x[ma_date.strftime("%B")+'CRG'] = 0
                #x[ma_date.strftime("%B")+'CMD'] = 0
            else:
                if n['inhand'] == 0:
                    chrg = 0
                    cmd = n[m]
                    #x[ma_date.strftime("%B")+'CRG'] = 0
                    #x[ma_date.strftime("%B")+'CMD'] = n[m]
                else:
                    if n['inhand'] >= n[m]:                        
                        chrg = n[m]
                        cmd = 0
                        #x[ma_date.strftime("%B")+'CRG'] = n[m]
                        #x[ma_date.strftime("%B")+'CMD'] = 0
                        n['inhand']-= n[m]
                    else:
                        chrg = n['inhand']
                        cmd = n[m] - n['inhand']
                        #x[ma_date.strftime("%B")+'CRG'] = n['inhand']
                        #x[ma_date.strftime("%B")+'CMD'] = n[m] - n['inhand']
                        n['inhand']= 0

            #if ma_date.month >= date.today().month:
            x[ma_date.strftime("%B")+'CRG'] = chrg+cmd
            #x[ma_date.strftime("%B")+'CMD'] = cmd

        Plan_charement.append(x)
        #print(x)


    for moins in months:
        ma_date = date(date.today().year, Get_Month_Digit(moins), date.today().day)
        ma_date = ma_date - timedelta(days=Transit_time_G[request.user.username])
        #if ma_date.month >= date.today().month:
        Month_PA.append(ma_date.strftime("%B"))
        Month_PA_Title.append(ma_date.strftime("%B")+'CRG')
        #Month_PA_Title.append(ma_date.strftime("%B")+'CMD')
        Month_PA_Title_Show.append('Chargement')
        #Month_PA_Title_Show.append('Commande')


    """ for pc in Plan_charement:
        print(pc) """

    Plan_charement_G[request.user.username] = Plan_charement
    Month_PA_G[request.user.username] = Month_PA
    Month_PA_Title_G[request.user.username] = Month_PA_Title
    Month_PA_Title_Show_G[request.user.username] = Month_PA_Title_Show
    #print(Month_PA_Title_G)

    

            
    

    months_g = []
    months_g_title = []
    for m in months:
        months_g.append(m+'_besoin')
        #months_g.append(m+'_chrg')
        #months_g.append(m+'_cmd')
        months_g_title.append(m[0:3]+'_BES')
        #months_g_title.append(m[0:3]+'_CHR')
        #months_g_title.append(m[0:3]+'_CMD')

    #print(months_g_title)

    Month_global[request.user.username] = months
    Month_title_global[request.user.username] = months
    Needs_global[request.user.username] = Needs
    Month_ORG[request.user.username] = months   

    #print('tab ',pdp_list_dic)



    context = {
        'months': months,
        
        'products' : tableau,
        'access':get_access(request.user.username),
        
        #'nbr_result':len(result_simulation_planification),
        }

    return render(request,'planification_chargement.html',context)

tableau_global = {}
nbr_month_global = {}



def Simulation_Chargement_calcule_V2(request):
    

   
    print('jours resant',Get_Days_Remaining())
    selected_id_sp = []
    Nbr_month = 0
    Transit_time = 0
    
    if request.method == "POST":
        selected_id_json = request.POST.get('articles')
       
        selected_id_sp = json.loads(selected_id_json)

        Nbr_month_str = request.POST.get('Nbr_month')  # on récupère en tant que str
        print('Nbr_month', Nbr_month_str)
        
        if Nbr_month_str and Nbr_month_str.strip().isdigit():
            Nbr_month = int(Nbr_month_str)
            global nbr_month_global
            nbr_month_global[request.user.username] = Nbr_month
        else:
            Nbr_month = 1  # ou 0, selon ton besoin

        print('Nbr_month', Nbr_month)
        Transit_time_str = request.POST.get('Transit_time')  # on récupère en tant que str
        print('Transit_time', Transit_time_str)

        if Transit_time_str and Transit_time_str.strip().isdigit():
            Transit_time = int(Transit_time_str)
            Transit_time_G[request.user.username] = Transit_time
        else:
            Transit_time = 90  # ou 0, selon ton besoin



    #Nbr_months = Nbr_month - 1

    global result_prd_filtre_dic,result_prd_filtre_simult_dic

    #Articles_PF_dic[request.user.username]
    global Bom_Lines
    result_simulation_planification = []
    
    print(selected_id_sp)    
    for rp in result_prd_filtre_simult_dic[request.user.username]:
        for l in selected_id_sp :
            print('rp',rp['id'],'l:',l[0])
            if rp['id'] == int(l[0]):
                rp['bom_id'] = float(l[1])

                #rp['virtu_qty'] = float(l[2])
                #rp['prevu_qty'] = float(l[3])
    forcast_cmp = []
    stock_min = []
    

    Stock_mins = []
    s_date = date.today()
    diff = relativedelta(s_date, date.today())

    

    
    Compoents_stock_dic = {}
    Compoents_forcast_dic = {}
    for art_prd in result_prd_filtre_simult_dic[request.user.username]:

        # Stock du produit fini
        stock_pf = art_prd['virtual_available']
        if stock_pf <= 0:
            stock_pf = 0

        # Récupération des composants de PF
        componet_pf = get_all_components_by_bom(
            Boms_dic[request.user.username],
            Bom_Lines_dic[request.user.username],
            int(art_prd['bom_id']),
            stock_pf
        )

        # PF stock to cmp stock 
        for cid, info in componet_pf.items():
            prd = get_product(cid, request)[0]
            code = prd['default_code']
            qty = info['qty']  # quantité calculée dans ta fonction

            # 👉 Si composant jamais ajouté → on l'ajoute
            if code not in Compoents_stock_dic:
                Compoents_stock_dic[code] = {
                    'code': code,
                    'name': prd['name'],
                    'stock': qty,   # quantité initiale
                    'sale_ok': prd['sale_ok'],
                    'purchase_ok': prd['purchase_ok'],
                    'categ_id': prd['categ_id'],
                    'virtual_available': prd['virtual_available']
                }
            else:
                # 👉 Composant présent → on cumule les quantités
                Compoents_stock_dic[code]['stock'] += qty

        
        # PF previon by month to cmp previson by month
        date_prevue_start = date.today()
        for i in range(1, nbr_month_global[request.user.username]+1):
            curent_date = date_prevue_start +  relativedelta(months=i-1)
            #print('current month',curent_date.strftime("%B"))
            # get prevision month i
            qty_prv = get_prevesion_quantity(request,art_prd['default_code'],curent_date.year,curent_date.month)

            # if the frist month calcule the remainig days of sales
            if i ==1:
                print('days left',jours_ouvrables_restants())
                qty_prv = int(qty_prv/22*jours_ouvrables_restants())
                
            print(art_prd['default_code'],':',qty_prv)
            # get all compoents for forcast
            componet_pf_forcast = get_all_components_by_bom(Boms_dic[request.user.username], Bom_Lines_dic[request.user.username], int(art_prd['bom_id']),qty_prv)
            for cid, info in componet_pf_forcast.items():
                #print("line dic :",cid,',',info['name'],',', info['qty'])
                prd = get_product(cid,request)[0]
                code = prd['default_code']
                month = curent_date.strftime("%B")
                f_qty = info['qty']

                # Si nouveau composant → on crée l'entrée
                if code not in Compoents_forcast_dic:
                    Compoents_forcast_dic[code] = {}

                # Si mois non créé → on initialise
                if month not in Compoents_forcast_dic[code]:
                    Compoents_forcast_dic[code][month] = 0

                # On cumule la quantité forecast
                Compoents_forcast_dic[code][month] += f_qty



       
        print('**********************************************')
        boms_prd = [bom for bom in Boms_dic[request.user.username] if bom['id'] == int(art_prd['bom_id'])]
        
        boms_cpts = []
        for bom_prd in boms_prd:
            bomlines_prd = [bl['bom_lines'] for bl in Bom_Lines_dic[request.user.username] if bom_prd['id'] == bl['bom_id']][0]
            #print('bom line',bomlines_prd)
            for bom_line_prd in bomlines_prd:
                item = {'id':bom_line_prd['product_id'][0],'qty':bom_line_prd['product_qty'],'bom_qty':bom_prd['product_qty']}
                boms_cpts.append(item)
    
        boms_cpts_clean = list({obj['id']: obj for obj in boms_cpts}.values())
        
        for cpt in boms_cpts_clean:
            prd = get_product(cpt['id'],request)[0]
            """ for i in range(1, diff.months+nbr_month_global[request.user.username]+1):
                f_date = s_date +  relativedelta(months=i-1)
                month_name_eta = f_date.strftime("%b-%Y")
                f_qty = cpt['qty']*get_prevesion_quantity(request,art_prd['default_code'],f_date.year,f_date.month)/cpt['bom_qty']

                #print('**************************************************************************')
                #print('i:',i,'month :',month_name_eta,'product',prd['default_code'],'f_qty:',f_qty)
                f_element = {
                    'code':prd['default_code'],
                    'qty':f_qty,
                    'month':month_name_eta,
                }
                #print(prd['default_code'],f_qty,month_name_eta,)
                forcast_cmp.append(f_element) """

            
            virtu_qty = cpt['qty']*art_prd['virtual_available']/cpt['bom_qty']
            prevu_qty = cpt['qty']*art_prd['prd_min_avrg']/cpt['bom_qty']
            
            
            composant = {'code':prd['default_code'],'name':prd['name'],'virtu_qty':virtu_qty,'prevu_qty':prevu_qty,'sale_ok':prd['sale_ok'],'purchase_ok':prd['purchase_ok'],'categ_id':prd['categ_id'],'virtual_available':prd['virtual_available']}
            stock_min.append(composant)

    """ for l in Compoents_stock:
        print(l) """

    """ for ll in Compoents_stock:
            print(ll) """


    print(Compoents_stock_dic)
    print(Compoents_forcast_dic)

    # Compoents_forcast = [
    #                         {'code': c, 'month': m, 'forcast': q}
    #                         for c, months in Compoents_forcast_dic.items()
    #                         for m, q in months.items()
    #                     ]
    # for pp in Compoents_forcast:
    #         print(pp)



    result = defaultdict(float)

    for item in forcast_cmp:
        key = (item['code'], item['month'])
        result[key] += item['qty']

    # Transformer le résultat en liste de dictionnaires
    final_list = [{'code': code, 'month': month, 'qty': qty} for (code, month), qty in result.items()]

    """ print('************************************')
    for mm in final_list:
        print(mm['code'],mm['month'],mm['qty'],) """

    lookup = {(item['code'], item['month']): item['qty'] for item in final_list}

    print(lookup.get(('LETDJ024', 'Dec-2025'), 0))

    cmp_data_sum = {}

    for component in stock_min:
        cmp_id = component['code']
        virtu_qty = component['virtu_qty']
        prevu_qty = component['prevu_qty']
        
        
        # Si le cmp_id existe déjà, ajouter à la quantité existante
        if cmp_id in cmp_data_sum:
            cmp_data_sum[cmp_id]['virtu_qty'] += virtu_qty
            cmp_data_sum[cmp_id]['prevu_qty'] += prevu_qty
            
        else:
            # Sinon, initialiser les informations pour ce cmp_id
            cmp_data_sum[cmp_id] = {
                'code': component['code'],
                'name': component['name'],
                'categ_id': component['categ_id'],
                'virtual_available': component['virtual_available'],
                'virtu_qty': virtu_qty,
                'prevu_qty': prevu_qty,
                
            # 'ecart': component['virtual_available']+virtu_qty+chrg_qty-prevu_qty
            }

        # Convertir le dictionnaire en liste d'objets (dictionnaires)
        Stock_mins = list(cmp_data_sum.values())
    

    cat_imporation_id = request.session.get('cat_imp_id', '')
    Stock_min_filtre = []
    
    
     
        #Stock_min_filtre = [prd for prd in Stock_mins if prd['categ_id'][0] == cat_imporation_id]
   
        
    Stock_min_filtre = Stock_mins

    today = date.today()
    date_Start = today+ timedelta(days=Transit_time_G[request.user.username])


    diff = relativedelta(date_Start, today)

    print(f"{diff.months} mois et {diff.days} jours")
    #calcule de couverture par moi

    print('Transit_time g', Transit_time_G[request.user.username])
    Month_PA_Toufik = []
    for i in range(1, diff.months+nbr_month_global[request.user.username]+1):
        date_etd = today +  relativedelta(months=i-1)
        date_eta = date_Start + relativedelta(months=i-1)
        date_etd_title = date_etd - timedelta(days=Transit_time_G[request.user.username])
        month_name_etd = date_etd.strftime("%B")
        Month_PA_Toufik.append(date_etd_title.strftime("%B"))
        month_name_eta = date_eta.strftime("%B")
        print('i:',i,'month etd:',month_name_etd,'month eta:',month_name_eta)
        for p in Stock_min_filtre:
            if i==1:
                qty = p['virtual_available']+p['virtu_qty']+ Get_ChargementByCode(request,p['code'],diff.months+i,Transit_time)-p['prevu_qty']-int(p['prevu_qty']/22*diff.days)
                p['qty'] = qty
            else:
                qty = p['qty']+Get_ChargementByCode(request,p['code'],diff.months+i,Transit_time)-p['prevu_qty']
                p['qty'] = qty

                if qty < -p['prevu_qty']:
                    qty = -p['prevu_qty']
            
            rsp = {
                    'code':p['code'],
                    'nom':p['name'],
                    'inhand':Get_InHandByCode(request,p['code']),
                    'prevu_qty':p['prevu_qty'],
                    'qty':qty,
                    
                    'month':month_name_etd,
                }
            
            result_simulation_planification.append(rsp)
            #print(rsp)
        result_simulation_planification_global[request.user.username] = result_simulation_planification
    
    #toufiikko
    
    


    months = []
    seen = set()
    [months.append(m['month']) for m in result_simulation_planification_global[request.user.username] if m['month'] not in seen and not seen.add(m['month'])]
    products = []
    seen_prd = set()
    [products.append(m['code']) for m in result_simulation_planification_global[request.user.username] if m['code'] not in seen_prd and not seen_prd.add(m['code'])]
    #print('hhhhhh',products)

    
    #months = list(set([m['month'] for m in result_simulation_planification_global[request.user.username]]))

    #print(months)
    pivot = defaultdict(lambda: {month: 0 for month in months})
    for entry in result_simulation_planification_global[request.user.username]:
        article = entry['code']
        month = entry['month']
        couverture = entry['qty']
        nom = entry['nom']
        inhand = entry['inhand']
        
        prevu_qty = entry['prevu_qty']
        pivot[article]['nom'] = nom
        pivot[article]['inhand'] = inhand
        pivot[article]['prevu_qty'] = prevu_qty
        
        pivot[article][month] = couverture

    tableau = []
    for article, ligne in sorted(pivot.items()):
        row = {'article': article, 'nom': ligne['nom'], 'inhand': ligne['inhand'], 'prevu_qty': ligne['prevu_qty']}
        row.update({month: ligne[month] for month in months})
        #print('row',row)
        tableau.append(row)
    
    Stock_min_filtre=[]

    

    Needs = []
    plan_appro = []
    plan_appro_real = []
    tableau_cmd_chrg = copy.deepcopy(tableau)

    for tab in tableau_cmd_chrg:
        x = {}
        x['article'] = tab['article']
        x['nom'] = tab['nom']
        x['prevu_qty'] = tab['prevu_qty']
        x['inhand'] = tab['inhand']
        

        flag = 0
        for m in months:
            
            if tab[m] >= 0:
                x[m] = 0
            else:
                x[m] =  abs(tab[m])
                
                flag += 1
        if flag > 0 :
            Needs.append(x)
            #print('need:',x)
    tableau_Needs = copy.deepcopy(Needs)

    global tableau_global
    tableau_global[request.user.username]=tableau_Needs

    Plan_charement = []
    Month_PA = []
    Month_PA_Title = []
    Month_PA_Title_Show = []
    
    today = date.today()


    for n in tableau_Needs:
        x = {}
        x['article'] = n['article']
        x['nom'] = n['nom']
        x['inhand'] = n['inhand']
        
        y = 0
        for m in months:
            ma_date = today +  relativedelta(months=y)
            #print(ma_date)
            chrg = 0
            cmd = 0
            if n[m]==0:
                chrg = 0
                cmd = 0
                
            else:
                if n['inhand'] == 0:
                    chrg = 0
                    cmd = n[m]
                    
                else:
                    if n['inhand'] >= n[m]:                        
                        chrg = n[m]
                        cmd = 0
                        
                        n['inhand']-= n[m]
                    else:
                        chrg = n['inhand']
                        cmd = n[m] - n['inhand']
                       
                        n['inhand']= 0

            
            x[ma_date.strftime("%B")+'CRG'] = chrg+cmd
            y+=1
           

        Plan_charement.append(x)
        #print(x)

    yy = 0
    for moins in months:
        ma_date = today +  relativedelta(months=yy)
        #if ma_date.month >= date.today().month:
        Month_PA.append(ma_date.strftime("%B"))
        Month_PA_Title.append(ma_date.strftime("%B")+'CRG')
        #Month_PA_Title.append(ma_date.strftime("%B")+'CMD')
        Month_PA_Title_Show.append('Chargement')
        #Month_PA_Title_Show.append('Commande')
        yy+=1

    """ for pc in Plan_charement:
        print(pc) """

    Plan_charement_G[request.user.username] = Plan_charement
    Month_PA_G[request.user.username] = Month_PA
    Month_PA_Title_G[request.user.username] = Month_PA_Title
    Month_PA_Title_Show_G[request.user.username] = Month_PA_Title_Show
    #print(Month_PA_Title_G)

    

            
    

    months_g = []
    months_g_title = []
    for m in months:
        months_g.append(m+'_besoin')
        #months_g.append(m+'_chrg')
        #months_g.append(m+'_cmd')
        months_g_title.append(m[0:3]+'_BES')
        #months_g_title.append(m[0:3]+'_CHR')
        #months_g_title.append(m[0:3]+'_CMD')

    #print(months_g_title)

    Month_global[request.user.username] = Month_PA_Toufik
    Month_title_global[request.user.username] = months 
    Needs_global[request.user.username] = Needs
    Month_ORG[request.user.username] = months   

    #print('tab ',pdp_list_dic)

    print('len besoin = ',len(tableau_global[request.user.username]))

    context = {
        'months': months,
        
        'products' :  tableau,
        'access':get_access(request.user.username),
        
        
        #'nbr_result':len(result_simulation_planification),
        }

    return render(request,'planification_chargement.html',context)



def Calcule_Besoin(request):

    context = {
        'months': Month_ORG[request.user.username],
        'months_toufik': Month_global[request.user.username],
        'months_title': Month_title_global[request.user.username],
        'products' : Needs_global[request.user.username],
        'access':get_access(request.user.username),
        
        #'nbr_result':len(result_simulation_planification),
        }

    return render(request,'Besoin.html',context)


def Plan_Approu(request):

    context = {
        'months_org': Month_ORG[request.user.username],
        'months': Month_PA_G[request.user.username],
        'months_data': Month_PA_Title_G[request.user.username],
        'months_data_show': Month_PA_Title_Show_G[request.user.username],
        'products' :  Plan_charement_G[request.user.username],
        'access':get_access(request.user.username),
        
        #'nbr_result':len(result_simulation_planification),
        }

    return render(request,'plan_approu.html',context)



def Stock_Min(request,*args,**kwargs):

    form = ArticleFilterForm(request.GET or None)
    if request.method == "POST":
        selected_id_json = request.POST.get('articles')
        #print(selected_id_cbn)
        global selected_id_cbn
        selected_id_cbn = json.loads(selected_id_json)
        request.session['selected_id_cbn'] = json.loads(selected_id_json)

    global result_prd_filtre_dic
    global Bom_Lines

   
        


    for rp in result_prd_filtre_dic[request.user.username]:
        for l in selected_id_cbn :
            if rp['default_code'] == l[0]:
                rp['product_min_qty1'] = float(l[1])
                rp['bom_id'] = float(l[2])


                
    stock_min = []
    Stock_mins = []
    for art_prd in  result_prd_filtre_dic[request.user.username]:
        boms_prd = [bom for bom in Boms_dic[request.user.username] if bom['id'] == art_prd['bom_id']]
        #print(boms_prd)
        boms_cpts = []
        for bom_prd in boms_prd:
            bomlines_prd = [bl['bom_lines'] for bl in Bom_Lines_dic[request.user.username] if bom_prd['id'] == bl['bom_id']][0]
            #bomlines_prd = get_bom_lines(bom_prd['id'])
            for bom_line_prd in bomlines_prd:
                item = {'id':bom_line_prd['product_id'][0],'qty':bom_line_prd['product_qty'],'bom_qty':bom_prd['product_qty']}
                boms_cpts.append(item)
       
        boms_cpts_clean = list({obj['id']: obj for obj in boms_cpts}.values())
        
        for cpt in boms_cpts_clean:
            qty_cpt = cpt['qty']*art_prd['product_min_qty1']/cpt['bom_qty']
            prd = get_product(cpt['id'],request)[0]
            
            composant = {'code':prd['default_code'],'name':prd['name'],'qty':qty_cpt,'sale_ok':prd['sale_ok'],'purchase_ok':prd['purchase_ok'],'categ_id':prd['categ_id'],'virtual_available':prd['virtual_available']}
            stock_min.append(composant)

    cmp_data_sum = {}

    for component in stock_min:
        cmp_id = component['code']
        cmp_qty = component['qty']
        
        # Si le cmp_id existe déjà, ajouter à la quantité existante
        if cmp_id in cmp_data_sum:
            cmp_data_sum[cmp_id]['cmp_qty'] += cmp_qty
        else:
            # Sinon, initialiser les informations pour ce cmp_id
            cmp_data_sum[cmp_id] = {
                'code': component['code'],
                'name': component['name'],
                'sale_ok': component['sale_ok'],
                'purchase_ok': component['purchase_ok'],
                'categ_id': component['categ_id'],
                'virtual_available': component['virtual_available'],
                #'ecart':component['virtual_available']-cmp_qty,
                'cmp_qty': cmp_qty
            }

        # Convertir le dictionnaire en liste d'objets (dictionnaires)
        Stock_mins = list(cmp_data_sum.values())
    
    for p in Stock_mins:
        p['ecart'] = p['virtual_available']-p['cmp_qty']
    
    form = ArticleFilterForm(request.GET or None)
    game = 0
    loc_prd = 0
    prduc_prd = 0
    ecart_f = 0
    Stock_min_filtre = []
    if form.is_valid():
        
        
        cat_imporation_id = request.session.get('cat_imp_id', '')
        if form.cleaned_data['gamme']:
            game = 1
            Stock_min_filtre += [prd for prd in Stock_mins if prd['categ_id'][0] == cat_imporation_id]
        if form.cleaned_data['loc_prd']:
            loc_prd = 1
            Stock_min_filtre += [prd for prd in Stock_mins if prd['categ_id'][0] != cat_imporation_id and prd['purchase_ok']==True]
        if form.cleaned_data['prduc_prd']:
            prduc_prd = 1
            Stock_min_filtre += [prd for prd in Stock_mins if prd['sale_ok']==False and prd['purchase_ok']==False]
        if form.cleaned_data['ecart']:
            ecart_f = 1
            Stock_min_filtre += [prd for prd in Stock_mins if prd['ecart']<=0]
    else:
         Stock_min_filtre = Stock_mins
    
    Stock_min_filtre.sort(key=lambda ap: ap['code'])
    #print('kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk')
    context = {
        'products' : Stock_min_filtre,
        'gamme':game,
        'loc_prd':loc_prd,
        'prduc_prd':prduc_prd,
        'ecart':ecart_f,
        'nbr_result':len(Stock_min_filtre),
        'access':get_access(request.user.username),
        }
    
     
    
    return render(request,'stock_min.html',context)







def can_prd_global(product_id):

    global Boms
    selected_boms = [bom for bom in Boms if bom['product_id'][0] ==product_id ]

    #print("selected bom ",selected_boms)
    list_prd_max = []
    if len(selected_boms)==0:
        return 0
    
    for bom in selected_boms:
        cp = can_product_global(bom['id'])
        
        list_prd_max.append(cp)
    
    if max(list_prd_max)<=0:
        return 0
    else:
        return max(list_prd_max)
    

























def get_cat_pf(user_id):
    cat = Category_user_set.objects.get(user=user_id)
    return cat.cat_parent_pf


def get_cat_mp(user_id):
    cat = Category_user_set.objects.get(user=user_id)
    return cat.cat_parent_mp
    


def get_user_cats(user_id):
    cat = Category_user_set.objects.get(user=user_id)
    return cat




def get_bom(bom_id,request):
    global Boms_dic
    result = [bm for bm in Boms_dic[request.user.username] if bm['id'] == bom_id]
    return result[0]

def get_bom_lines1(id_bom,gamme,request):
    par = get_paramettre(request.user.username)
    common = xmlrpc.client.ServerProxy(f'{par.link_db}/xmlrpc/2/common')
    models = xmlrpc.client.ServerProxy(f'{par.link_db}/xmlrpc/2/object')

    uid = common.authenticate(par.database, request.user.username, request.session.get('pw', ''), {})
    fields6 = ['product_id', 'product_qty']
    bom_data = models.execute_kw(par.database, uid, request.session.get('pw', ''), 'mrp.bom', 'read', [id_bom], {'fields': ['bom_line_ids']})
    dom = [('product_id.categ_id', '=', gamme)]
    bom_line_ids = bom_data['bom_line_ids'] if bom_data else []
    dom99 = [bom_line_ids]
    bom_lines = models.execute_kw(par.database, uid, request.session.get('pw', ''), 'mrp.bom.line', 'read', [bom_line_ids], {'fields': fields6})
    return bom_lines







def Stock_Min1(request,*args,**kwargs):
    global result_prd
    stock_min = []
    Stock_mins = []
    for art_prd in  result_prd:
        boms_prd = [bom for bom in Boms if bom['product_id'][0] == art_prd['id']]
        boms_cpts = []
        for bom_prd in boms_prd:
            bomlines_prd = [bl['bom_lines'] for bl in Bom_Lines if bom_prd['id'] == bl['bom_id']][0]
            #bomlines_prd = get_bom_lines(bom_prd['id'])
            for bom_line_prd in bomlines_prd:
                item = {'id':bom_line_prd['product_id'][0],'qty':bom_line_prd['product_qty'],'bom_qty':bom_prd['product_qty']}
                boms_cpts.append(item)
       
        boms_cpts_clean = list({obj['id']: obj for obj in boms_cpts}.values())
        
        for cpt in boms_cpts_clean:
            qty_cpt = cpt['qty']*art_prd['product_min_qty']/cpt['bom_qty']
            prd = get_product(cpt['id'])[0]
            composant = {'code':prd['default_code'],'name':prd['name'],'qty':qty_cpt}
            stock_min.append(composant)

    cmp_data_sum = {}

    for component in stock_min:
        cmp_id = component['code']
        cmp_qty = component['qty']
        
        # Si le cmp_id existe déjà, ajouter à la quantité existante
        if cmp_id in cmp_data_sum:
            cmp_data_sum[cmp_id]['cmp_qty'] += cmp_qty
        else:
            # Sinon, initialiser les informations pour ce cmp_id
            cmp_data_sum[cmp_id] = {
                'code': component['code'],
                'name': component['name'],
                'cmp_qty': cmp_qty
            }

        # Convertir le dictionnaire en liste d'objets (dictionnaires)
        Stock_mins = list(cmp_data_sum.values())
    
   
    
    Stock_mins.sort(key=lambda ap: ap['code'])
    context = {
        'products' : Stock_mins,
        'nom':'Produits de la boutique',
        'access':get_access(request.user.username),
        }
    
    

    return render(request,'stock_min.html',context)

result_prd_filtre = []

result_prd_filtre_dic = {}

def get_category_pf(cat_name):
    catrgory = [cat for cat in categories if cat_name == cat['name']]
    return catrgory[0]['id']

def get_category_mp(cat_name):
    catrgory = [cat for cat in categories if cat_name == cat['name']]
    return catrgory[0]['id']

def get_paramettre(user_id):
    cat = Category_user_set.objects.get(username=user_id)
    return cat

def get_company(Company_code):
    company = None
    company = Company_Config.objects.get(Company_code=Company_code)
    return company

def get_company_byid(Company_code):
    company = None
    company = Company_Config.objects.get(Company_id=Company_code)
    return company

def get_cat_impo_id(user_id):
    cat = Category_user_set.objects.get(user=user_id)
    cat_name = cat.cat_imporation
    global categories
    catrgory = [cat for cat in categories if cat_name == cat['name']]
    return catrgory[0]['id']

def get_opr_type(user_id,company_id):
    
    cat = Category_user_set.objects.get(user=user_id)
    opr_typ = 0
    if company_id ==1:
        opr_typ = cat.type_oper1
    if company_id ==3:
        opr_typ = cat.type_oper2
    if company_id ==5:
        opr_typ = cat.type_oper3

    return opr_typ




def Chargement_list(request,*args,**kwargs):

    chrg = Chargement.objects.filter(Company = request.session['current_company_id'])
    #Get_Chargement('2025-04-22')
    context = {
        'liste':chrg,
        'access':get_access(request.user.username),
    }

    return render(request,'chargement.html',context)


def Commande_list(request,*args,**kwargs):

    chrg = Commande.objects.filter(Company = request.session['current_company_id'])
    #Get_Chargement('2025-04-22')
    context = {
        'liste':chrg,
        'access':get_access(request.user.username),
    }

    return render(request,'commande.html',context)

eta = ''
Nbr_month = 0

import datetime
import calendar
from dateutil.relativedelta import relativedelta

def jours_ouvrables_restants():
    today = date.today()
    # Dernier jour du mois courant
    last_day = date(today.year, today.month, calendar.monthrange(today.year, today.month)[1])

    jours_ouvrables = 0
    current_day = today

    while current_day <= last_day:
        # weekday() : lundi=0 ... dimanche=6
        if current_day.weekday() not in (4, 5):  # exclut vendredi (4) et samedi (5)
            jours_ouvrables += 1
        current_day += timedelta(days=1)
    
    return jours_ouvrables


def Get_Days_Remaining():

    today = datetime.date.today()
    year = today.year
    month = today.month

    # Dernier jour du mois
    if month == 12:
        next_month = datetime.date(year + 1, 1, 1)
    else:
        next_month = datetime.date(year, month + 1, 1)

    last_day = next_month - datetime.timedelta(days=1)

    # Compter les jours restants (à partir de demain) sans vendredi (4) ni samedi (5)
    days_remaining = 0
    current_day = today + datetime.timedelta(days=1)

    while current_day <= last_day:
        if current_day.weekday() not in [4, 5]:  # 4 = vendredi, 5 = samedi
            days_remaining += 1
        current_day += datetime.timedelta(days=1)

    return days_remaining

from django.db.models import F, ExpressionWrapper, DateField

def Get_ChargementByCode(request,code_pf,nbr_munth,transit_time):

    today = datetime.date.today()
    new_date = today + relativedelta(months=nbr_munth)
    df = new_date.replace(day=15)

    if new_date.month == 1:
        dd = new_date.replace(year=new_date.year - 1, month=12, day=15)
    else:
        dd = new_date.replace(month=new_date.month - 1, day=15)

    # Annoter Etar + 90 jours
    etar_plus_90 = ExpressionWrapper(F('Etd') + timedelta(days=transit_time), output_field=DateField())

    # Filtrer sur Etar + 90 jours ∈ [dd, df]
    chrg = Chargement.objects.annotate(Etar90=etar_plus_90)\
        .filter(Etar90__range=(dd, df), Etat__in=['Expédé', 'Arrivé'])\
        .values('Num')

    nums = list(chrg.values_list('Num', flat=True))

    result = Chargement_lines.objects.filter(Num__in=nums, Product=code_pf)\
        .values('Product')\
        .annotate(Qty=Sum('Qty'))

    if len(result) == 0:
        return 0

    return result[0]['Qty']


def Get_InHandByCode(request,code_pf):

    chrg_val = 0
    cmd_val = 0
    x = Chargement.objects.annotate()\
        .exclude(Etat='Brouillant')\
        .values('Num')

    nums = list(x.values_list('Num', flat=True))
    chrg = Chargement_lines.objects.filter(Num__in=nums,Product=code_pf)\
        .values('Product')\
        .annotate(Qty=Sum('Qty'))

    if len(chrg) == 0:
       chrg_val = 0
    else:
        chrg_val = chrg[0]['Qty']
    
    cmd = Commande_lines.objects.filter(Product=code_pf)\
        .values('Product')\
        .annotate(Qty=Sum('Qty'))

    if len(cmd) == 0:
       cmd_val = 0
    else:
        cmd_val = cmd[0]['Qty']


    return cmd_val-chrg_val




def Get_Chargement(request):
    
    if request.method == 'POST':
        global eta,Nbr_month
        eta =  request.POST.get('eta')
        Nbr_month =  request.POST.get('Nbr_month')

    #print('eta = ',eta)
    date_obj = datetime.strptime(eta, "%Y-%m-%d").date()
    now = datetime.now().date()
    diff = date_obj - now

    print('date_obj = ',date_obj,'mois = ',Nbr_month,'jours = ',diff.days)
    liste = []
    chrg = Chargement.objects.filter(Etar__lte=date_obj,Etat__in=['Expédé','Arrivé']).values('Num')
    nums = list(chrg.values_list('Num', flat=True))

    result = Chargement_lines.objects.filter(Num__in = nums).values('Product')\
        .annotate(Qty=Sum('Qty'))
    
    
    for cvr in PF_SM_dic[request.user.username]:
        smj = cvr['product_min_qty']/22

        y = next((a for a in result if a["Product"] == cvr['default_code']), None)

        if y :
            x = {
                    'code':cvr['default_code'],
                    'nom':cvr['name'],
                    'stock':cvr['virtual_available'],
                    'qty_planifie':cvr['prd_max'],
                    'stock_min':cvr['product_min_qty'],
                    'qty_chrg':y['Qty'],
                    'couverture_globale':cvr['virtual_available']+cvr['prd_max']+y['Qty'],
                    #'stock_prevue':cvr['virtual_available']+cvr['prd_max']+y['Qty']-(cvr['product_min_qty']+int(Nbr_month)*cvr['product_min_qty']),
                    'stock_prevue':cvr['virtual_available']+cvr['prd_max']+y['Qty']-int(diff.days*cvr['product_min_qty']/22),
                }
            liste.append(x)
        else:
            x = {
                    'code':cvr['default_code'],
                    'nom':cvr['name'],
                    'stock':cvr['virtual_available'],
                    'qty_planifie':cvr['prd_max'],
                    'stock_min':cvr['product_min_qty'],
                    'qty_chrg':0,
                    'couverture_globale':cvr['virtual_available']+cvr['prd_max'],
                    #'stock_prevue':cvr['virtual_available']+cvr['prd_max']-(cvr['product_min_qty']+int(Nbr_month)*cvr['product_min_qty']),
                    'stock_prevue':cvr['virtual_available']+cvr['prd_max']-int(diff.days*cvr['product_min_qty']/22),
                }
            liste.append(x)
        
        



    #print(list(result))



    context = {
        'result':liste,
        'date':date_obj,
        'Nbr_month':Nbr_month,
        'access':get_access(request.user.username),
    }

    return render(request,'planification_chargement.html',context)


result_prd_filtre_simult_dic = {}

def Simulation_Chargement(request):
    
    global result_prd_dic,Articles_PF_dic
    
    print('simulation')
    result_prd_filtre = []
    default_code =''
    form = ArticleFilterForm(request.GET or None)
    if form.is_valid():
        if form.cleaned_data['default_code']:
            default_code = form.cleaned_data['default_code']
            result_prd_filtre = [art  for art in Articles_PF_dic[request.user.username] if form.cleaned_data['default_code'].lower() in art['default_code'].lower() or form.cleaned_data['default_code'].lower() in art['name'].lower() ]
        else:
            result_prd_filtre = Articles_PF_dic[request.user.username]
    else:
        result_prd_filtre = Articles_PF_dic[request.user.username]

    result_prd_filtre.sort(key=lambda ap: ap['default_code'])
    


    global result_prd_filtre_simult_dic
    result_prd_filtre_simult_dic[request.user.username] = result_prd_filtre
    #print(result_prd_filtre_dic[request.user.username])
    global Boms_dic
    #print(Boms)
    context = {
        'products' : result_prd_filtre_simult_dic[request.user.username],
        'nom':default_code,
        'boms':Boms_dic[request.user.username],
        'nbr_result':len(result_prd_filtre_simult_dic[request.user.username]),
        'access':get_access(request.user.username),
        }
    
    
    return render(request,'simulation_planification.html',context)



def add_chargement(request,*args,**kwargs):

    #print('hhhhh')

    context = {
        'Articles':Articles_MP_dic_imp[request.user.username],
        'access':get_access(request.user.username),
    }

    return render(request,'chargement_detail.html',context)

def import_chargement(request,*args,**kwargs):

    #print('hhhhh')

    context = {
        #'Articles':Articles_MP_dic_imp[request.user.username],
        'access':get_access(request.user.username),
    }

    return render(request,'chargement_import.html',context)

def import_commande(request,*args,**kwargs):

    #print('hhhhh')

    context = {
        #'Articles':Articles_MP_dic_imp[request.user.username],
    }

    return render(request,'commande_import.html',context)

def add_commande(request,*args,**kwargs):

    #print('hhhhh')

    context = {
        'Articles':Articles_MP_dic_imp[request.user.username],
        'access':get_access(request.user.username),
    }

    return render(request,'commande_detail.html',context)

num = ''
def chargement_show(request,*args,**kwargs):

    #print('hhhhh')

    global num
    
    if request.method == 'POST':
        num =  request.POST.get('num')
        
    
    chrg_entete = Chargement.objects.filter(Num = num).values()
    chrg_lines = Chargement_lines.objects.filter(Num = num).values()

    
    #print(chrg_entete)

    

    context = {
        'chrg_entete':chrg_entete,
        'chrg_lines':chrg_lines,
        'Articles':Articles_MP_dic_imp[request.user.username],
        'access':get_access(request.user.username),
       
    }

    return render(request,'chargement_show.html',context)



def Commande_show(request,*args,**kwargs):

    #print('hhhhh')

    global num
    
    if request.method == 'POST':
        num =  request.POST.get('num')
        
    
    chrg_entete = Commande.objects.filter(Num = num).values()
    chrg_lines = Commande_lines.objects.filter(Num = num).values()

    
    #print(chrg_entete)

    

    context = {
        'chrg_entete':chrg_entete,
        'chrg_lines':chrg_lines,
        'Articles':Articles_MP_dic_imp[request.user.username],
        'access':get_access(request.user.username),
       
    }

    return render(request,'commande_show.html',context)


def add_chargement_lines(request):

    if request.method == 'POST':
        num =  request.POST.get('num')
        etd =  request.POST.get('etd')
        eta =  request.POST.get('eta')
        comment =  request.POST.get('comment')
        data_json = request.POST.get('articles')
        try:
            articles = json.loads(data_json)
            #print(articles)  # Liste de dictionnaires [{code:..., quantite:...}, ...]
            #print(num,' ',etd,' ',eta)
            chrg = Chargement.objects.create(
                Num = num,
                Etd = etd,
                Eta = eta,
                Etdr = etd,
                Comment =  comment,
                Etar = eta,
                Etat  = 'Brouillant',
                Company = request.session['current_company_id'],
            )
            for art in articles:

                print(art['code'],' ',art['quantite'])

                chrg_lines = Chargement_lines.objects.create(
                    Num = chrg.Num,
                    Product = art['code'],
                    Product_Name = art['name'],
                    Qty  = art['quantite'],
                )
            
        except json.JSONDecodeError:
            return JsonResponse({"error": "Invalid JSON"}, status=400)
    

   
    return JsonResponse({"message": 1})


def add_chargement_lines_IMP(request):

    if request.method == 'POST':
        num =  request.POST.get('num')
        etd =  request.POST.get('etd')
        eta =  request.POST.get('eta')
        data_json = request.POST.get('articles')
        try:
            articles = json.loads(data_json)
            #print(num,' ',etd,' ',eta)
            #print(articles)  # Liste de dictionnaires [{code:..., quantite:...}, ...]
           

            chrg = Chargement.objects.create(
                Num = num,
                Etd = etd,
                Eta = eta,
                Etdr = etd,
                Comment =  '',
                Etar = eta,
                Etat  = 'Brouillant',
                Company = request.session['current_company_id'],
            )
            for art in articles:
                #print(art['code'],' ',art['quantite'])
                #print('prd name ',art['code'],get_product_by_code(art['code'],request)[0]['name'])

                chrg_lines = Chargement_lines.objects.create(
                    Num = chrg.Num,
                    Product = art['code'],
                    Product_Name = get_product_by_code(art['code'],request)[0]['name'],
                    Qty  = art['quantite'],
                )
            
        except json.JSONDecodeError:
            return JsonResponse({"error": "Invalid JSON"}, status=400)
    

   
    return JsonResponse({"message": 1})



def Import_Prevision_file(request):
    if request.method == 'POST':
        annee = int(request.POST.get('annee'))
        mois = int(request.POST.get('mois'))  # exemple : 10
        data_json = request.POST.get('articles')

        try:
            articles = json.loads(data_json)

            for art in articles:
                champ_mois = f"_{mois}"  # => "_10" pour octobre
                prv_sale, created = prevsion_vente.objects.get_or_create(
                    Annee=annee,
                    Product_Code=art['code'],
                    company=request.session['current_company_id'],
                    defaults={'Product_Name': art['name']}
                )

                # Mettre à jour dynamiquement la colonne du mois concerné
                setattr(prv_sale, champ_mois, art['quantite'])
                prv_sale.save()

        except json.JSONDecodeError:
            return JsonResponse({"error": "Invalid JSON"}, status=400)

    return JsonResponse({"message": 1})




def add_commande_lines(request):

    if request.method == 'POST':
        num =  request.POST.get('num')
        etd =  request.POST.get('etd')
        comment =  request.POST.get('comment')
        data_json = request.POST.get('articles')
        try:
            articles = json.loads(data_json)
            #print(articles)  # Liste de dictionnaires [{code:..., quantite:...}, ...]
            #print(num,' ',etd,' ',eta)
            chrg = Commande.objects.create(
                Num = num,
                Date_BC = etd,
                
                
                Comment =  comment,
                
                
                Company = request.session['current_company_id'],
            )
            for art in articles:
                #print(art['code'],' ',art['quantite'])
                chrg_lines = Commande_lines.objects.create(
                    Num = chrg.Num,
                    Product = art['code'],
                    Product_Name = art['name'],
                    Qty  = art['quantite'],
                )
            
        except json.JSONDecodeError:
            return JsonResponse({"error": "Invalid JSON"}, status=400)
    

   
    return JsonResponse({"message": 1})

def add_commande_lines_IMP(request):

    if request.method == 'POST':
        num =  request.POST.get('num')
        etd =  request.POST.get('etd')
        
        data_json = request.POST.get('articles')
        try:
            articles = json.loads(data_json)
            #print(articles)  # Liste de dictionnaires [{code:..., quantite:...}, ...]
            #print(num,' ',etd,' ',eta)
            chrg = Commande.objects.create(
                Num = num,
                Date_BC = etd,
                Comment =  '',
                Company = request.session['current_company_id'],
            )
            for art in articles:
                #print(art['code'],' ',art['quantite'])
                chrg_lines = Commande_lines.objects.create(
                    Num = chrg.Num,
                    Product = art['code'],
                    Product_Name = get_product_by_code(art['code'],request)[0]['name'],
                    Qty  = art['quantite'],
                )
            
        except json.JSONDecodeError:
            return JsonResponse({"error": "Invalid JSON"}, status=400)
    

   
    return JsonResponse({"message": 1})



def update_chargement_lines(request):

    if request.method == 'POST':
        num =  request.POST.get('num')
        etd =  request.POST.get('etd')
        eta =  request.POST.get('eta')
        stat =  request.POST.get('stat')
        comment =  request.POST.get('comment')
        data_json = request.POST.get('articles')
        try:
            articles = json.loads(data_json)
            #print(articles)  # Liste de dictionnaires [{code:..., quantite:...}, ...]
            #print(num,' ',etd,' ',eta)


            chrg = Chargement.objects.get(Num = num)

            chrg.Etdr = etd
            chrg.Etar = eta
            chrg.Etat = stat
            chrg.Comment = comment
            chrg.save()

            chrg_lines = Chargement_lines.objects.filter(Num=num)
            chrg_lines.delete()

            for art in articles:
                print(art['code'],' ',art['quantite'])
                chrg_lines = Chargement_lines.objects.create(
                    Num = num,
                    Product = art['code'],
                    Product_Name = art['name'],
                    Qty  = art['quantite'],
                )
            
        except json.JSONDecodeError:
            return JsonResponse({"error": "Invalid JSON"}, status=400)
    

   
    return JsonResponse({"message": 1})



def update_commande_lines(request):

    if request.method == 'POST':
        num =  request.POST.get('num')
        etd =  request.POST.get('etd')
        comment =  request.POST.get('comment')
        data_json = request.POST.get('articles')
        try:
            articles = json.loads(data_json)
            #print(articles)  # Liste de dictionnaires [{code:..., quantite:...}, ...]
            #print(num,' ',etd,' ',eta)


            chrg = Commande.objects.get(Num = num)

            chrg.Etdr = etd
            
            chrg.Comment = comment
            chrg.save()

            chrg_lines = Commande_lines.objects.filter(Num=num)
            chrg_lines.delete()

            for art in articles:
                print(art['code'],' ',art['quantite'])
                chrg_lines = Commande_lines.objects.create(
                    Num = num,
                    Product = art['code'],
                    Product_Name = art['name'],
                    Qty  = art['quantite'],
                )
            
        except json.JSONDecodeError:
            return JsonResponse({"error": "Invalid JSON"}, status=400)
    

   
    return JsonResponse({"message": 1})


def Stock_ERP(request):
    par = get_paramettre(request.user.username)
    models = xmlrpc.client.ServerProxy(f'{par.link_db}/xmlrpc/2/object')    
    dom_PF = [('categ_id.parent_id.name', 'ilike',par.cat_parent_pf),('sale_ok', '=', True),('active', '=', True)]
    champs_PF = ['id','default_code','name','qty_available','virtual_available']
    
    Articles_PF = models.execute_kw(
        par.database,
        request.session.get('uid', ''),
        request.session.get('pw', ''),
        'product.product',
        'search_read',  # Odoo model name and method
        [dom_PF],  # Domain for filtering the records (empty list fetches all)
        {
            'fields': champs_PF,  # Champs à récupérer
            'context': {'lang': 'fr_FR','location':int(par.location_delivry)}
        }  # Fields you want to retrieve
    )

    Articles_PF_clean = []
    for p in Articles_PF:
        if p['qty_available']> 0:
            print('article magasin',p)
            Articles_PF_clean.append(p)
    global Articles_PF_ERP_global
    Articles_PF_ERP_global[request.user.username] = Articles_PF_clean
    context = {
        
    'Articles':Articles_PF_ERP_global[request.user.username],
    'access':get_access(request.user.username),
       
    }

    return render(request,'create_trasrfert_ERP.html',context) 

Articles_PF_ERP_global = {}


from django.http import JsonResponse
import datetime as dt
import xmlrpc.client

def Transfert_Inter_Composany(request):

    """
    il faut le parametrage de système 
    - creation api mono
    - creation api bms
    - partner D5 D6 D7 enlever la societe
    - parnter D30 MONO et soukoy enlever la soceite
    """
    try:
        start_time = time.time()
        par = get_paramettre(request.user.username)
        common = xmlrpc.client.ServerProxy(f'{par.link_db}/xmlrpc/2/common')
        models = xmlrpc.client.ServerProxy(f'{par.link_db}/xmlrpc/2/object')
        global Articles_PF_ERP_global

        order_line_OUT = []
        order_line_IN = []
        dict_company = {}
        
        for p in Articles_PF_ERP_global[request.user.username]:
            company = get_company(p['default_code'][0])
            # get product cvompany
            if company and p['virtual_available'] > 0:
                # create lien out by company
                line_OUT = (0, 0, {
                    'product_id': p['id'],
                    'product_uom_qty': p['virtual_available'],
                    'location_id': par.location_delivry,
                    'confirmed_date': dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                    'promised_date': dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                })
                # add line out to dic pd liens out
                order_line_OUT.append({'id_cmp': company.Company_id, 'line': line_OUT})
                # create line in product by compony 
                line_IN = (0, 0, {
                    'product_id': p['id'],
                    'product_qty': p['virtual_available'],
                    'price_unit': 1,
                    'location_dest_id': company.Company_location_reception,
                    'date_planned': dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                    'name': p['name'],
                })
                # add line in to dic prd lienes in
                order_line_IN.append({'id_cmp': company.Company_id, 'line': line_IN})
                # add comoany id to dic companies
                dict_company[company.Company_id] = company


        if not dict_company:
            return JsonResponse({"Response": "Aucun transfert n’a été généré"})
        print('rani hna 1')
        for i in dict_company:
            # get prodcut out  for  company i
            var_out_list = [l['line'] for l in order_line_OUT if l['id_cmp'] == i]
            # get prodcut in  for  company i
            var_in_list = [l['line'] for l in order_line_IN if l['id_cmp'] == i]
            print('rani hna 2')
            if not var_out_list:
                continue

            try:
                # create  delivery for  company i
                sale_order_id = models.execute_kw(
                    par.database, request.session.get('uid', ''), request.session.get('pw', ''),
                    'sale.order', 'create', [{
                        'type_id': models.execute_kw(par.database, request.session.get('uid', ''), request.session.get('pw', ''),
                                                     'ir.model.data', 'xmlid_to_res_id', ['insidjam_transfer_2_steps.transfer_out_type']),
                        'location_id': par.warehouse_delivry, # D5
                        'origin': 'manufacturing',
                        'partner_id': dict_company[i].Company_partner_reception, # D30 BMS MONO SOUKOY 
                        'order_line': var_out_list,
                        
                    }]
                )
                # validete delevery for company i 
                models.execute_kw(par.database, request.session.get('uid', ''), request.session.get('pw', ''),
                                  'sale.order', 'action_button_confirm', [[sale_order_id]])
                print('rani hna 3')
                # create reception for commany i
                if i ==1:
                    # if same company 
                    print('rani hna 3.2')
                    purchase_order_id = models.execute_kw(
                        par.database, request.session.get('uid', ''), request.session.get('pw', ''),
                        'purchase.order', 'create', [{
                        'type_id': models.execute_kw(par.database,request.session.get('uid', '') , request.session.get('pw', ''),
                                                        'ir.model.data', 'xmlid_to_res_id', ['insidjam_transfer_2_steps.transfer_in_type']),
                        'location_id': dict_company[i].Company_location_reception,  # location reception for  company D30 BMS                 
                        'pricelist_id': dict_company[i].price_list, # liste price
                        'origin': 'Transfert inter société', # note
                        'partner_id': par.partner_delivry, # adresse de location develry D5
                        'order_line': var_in_list, # prd in
                        'company_id':dict_company[i].Company_id, #company bms 
                        'operating_unit_id':dict_company[i].Operation_unit, # BU
                            
                        }]
                    )
                    # validate reception
                    models.exec_workflow(par.database, request.session.get('uid', ''), request.session.get('pw', ''),
                                     'purchase.order', 'purchase_confirm', purchase_order_id)
                else:
                    # not same company
                    print('rani hna 3.3')
                    context_second_company = {'company_id': i}
                    uid_second = common.authenticate(par.database, dict_company[i].api_user, dict_company[i].api_password, context_second_company)
                    print('uid_second=',uid_second)
                    print('rani hna 3.5')
                    purchase_order_id = models.execute_kw(
                        par.database, uid_second, dict_company[i].api_password,
                        'purchase.order', 'create', [{
                        'type_id': models.execute_kw(par.database,uid_second , dict_company[i].api_password,
                                                        'ir.model.data', 'xmlid_to_res_id', ['insidjam_transfer_2_steps.transfer_in_type']),
                        
                        'location_id': dict_company[i].Company_location_reception, #  D30 mono or soukoy         
                        'pricelist_id': dict_company[i].price_list,
                        'origin': 'Transfert inter société',
                        'partner_id': par.partner_delivry, #D5 bms
                        'order_line': var_in_list,
                            
                        }],
                        {'context': context_second_company}
                    )
                    # validate reception not same company 
                    models.exec_workflow(par.database, uid_second, dict_company[i].api_password,
                                     'purchase.order', 'purchase_confirm', purchase_order_id)
                print('rani hna 4')
                # Confirmation des documents
                

                

            except xmlrpc.client.Fault as fault:
                print({"error": f"Erreur XML-RPC : {fault.faultString} (Code : {fault.faultCode})"})
                return JsonResponse({"error": f"Erreur XML-RPC : {fault.faultString} (Code : {fault.faultCode})"})

            except Exception as e:
                print({"error": f"Une erreur inattendue s'est produite : {str(e)}"})
                return JsonResponse({"error": f"Une erreur inattendue s'est produite : {str(e)}"})
        end_time = time.time()  # Temps de fin
        execution_time = end_time - start_time
        print('temps excecution est :',execution_time)
        return JsonResponse({"Response": "Les transferts des produits finis ont été générés avec succès"})

    except Exception as e:
        print(f"Une erreur inattendue s'est produite : {str(e)}")
        return JsonResponse({"error": f"Erreur interne : {str(e)}"}, status=333)


def home(request):
    #MES(request,494,32994,10000)
    
    return render(request,'home.html',{'access':get_access(request.user.username),})


def get_access(user):
    access_user = Access.objects.get(user_id=user)
    return access_user