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,Q
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 = []

Achats_local_dic = {}

Produces_local_dic = {}

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
            request.session['capacite_prod'] = par.capacite_prod

            
            #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','marque_id']
            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

            #********************************** Achat local *******************************************************
            #[['location_id', '=', 489], ['order_type_id', '!=', 13], ['state', '!=', 'cancel'], ['state', '!=', 'done']]

            dom_achat_local = [
                ['order_type_id', '=', 7],
                ['state', '!=', 'draft'],
                ['state', '!=', 'done'],
                ['state', '!=', 'cancel']
            ]

            # Champs à agréger
            fields_achat_local = ['product_qty']
            # Groupement par produit
            groupby_Achat_loc = ['product_id']

            # Appel Odoo
            Achats_local = models.execute_kw(
                par.database,
                request.session.get('uid', ''),
                request.session.get('pw', ''),
                'purchase.order.line',
                'read_group',
                [dom_achat_local, fields_achat_local, groupby_Achat_loc],
                {
                    'context': {'lang': 'fr_FR'}
                }
            )

            #print('achats local', Achats_local)

            # Nettoyage résultat
            cleaned_result_Achat_local = {}

            for rec in Achats_local:
                # rec['product_id'] = [id, name]
                product_id = rec['product_id'][0] if rec.get('product_id') else None
                qty = rec.get('product_qty', 0)

                cleaned_result_Achat_local[product_id] = qty

            # Sauvegarde globale
            global Achats_local_dic
            Achats_local_dic[request.user.username] = cleaned_result_Achat_local

            #print('achats local cleaned', cleaned_result_Achat_local)

            #********************************************************************************************************

            #print('hhhhhhh',Articles_MP_dic_imp[request.user.username])
            #****************************************prodcution SF***************************************************
            champs_OFs = ['product_id','remaining_qty']
            dom_OFs = [
                ['product_id.marque_id', 'ilike', par.marque],
               
                ['state', 'not in', ['draft', 'cancel', 'done', 'closing_control']],
            ]
            ofs = models.execute_kw(
                par.database,
                request.session.get('uid', ''), 
                request.session.get('pw', ''),
                'mrp.production', 'search_read',  # Odoo model name and method
                [dom_OFs],  # Domain for filtering the records (empty list fetches all)
                {'fields': champs_OFs,  # Champs à récupérer
                 'context': {'lang': 'fr_FR'}}  # Fields you want to retrieve
            )
            #print(ofs)
            ofs_valides = [of for of in ofs if of['remaining_qty'] > 0]
            result = {}
            for of in ofs_valides:
                pid = of['product_id'][0]
                result[pid] = result.get(pid, 0) + of['remaining_qty']

            Produces_local_dic[request.user.username] = result
            #print(result)

            #print(ofs_valides)
            #********************************************************************************************************
            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_bom2(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_bom2(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_all_components_by_bom(boms, bom_lines, bom_id, qty=1.0, result=None, root=True):
    """
    Retourne un dict des sous-assemblages + composants finaux,
    mais exclut le produit fini principal.
    """
    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:
        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

    # 👉 On N’AJOUTE PAS le produit principal (root=True)
    if not root:
        if product_id not in result:
            result[product_id] = {'name': product_name, 'qty': 0.0}
        result[product_id]['qty'] += qty

    # Récupérer les lignes
    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

    # Boucler sur les composants
    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 = qty * (line_qty / bom_qty)

        # Vérifier si c’est un sous-assemblage
        sub_bom = next((b for b in boms if b['product_id'][0] == comp_id), None)

        if sub_bom:
            # Ajouter comme sous-assemblage
            if comp_id not in result:
                result[comp_id] = {'name': comp_name, 'qty': 0.0}
            result[comp_id]['qty'] += comp_total

            # Récursion
            get_all_components_by_bom(boms, bom_lines, sub_bom['id'], comp_total, result, root=False)
        else:
            # Composant final
            if comp_id not in result:
                result[comp_id] = {'name': comp_name, 'qty': 0.0}
            result[comp_id]['qty'] += comp_total

    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 get_capacite_prod(request, product_code, annee):
    """
    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
    

    try:
        obj = prevsion_vente.objects.filter(
        Product_Code=product_code,
        Annee=annee,
        company=request.session.get('current_company_id', '')
    )   .first()

        if obj:
            return  obj.capacite_prod
        return 0

    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)
    
    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)
        if par.capacite_prod:
            prevision_avrg = get_capacite_prod(request,pf['default_code'],date_pr.year)
        else:
            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 = Couverture_By_product(request,prd_code,prd_vrt_st)
            
        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)
    
    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']
        stock_init = Get_Stock_Init(request,pf['default_code'])
        prd_min = get_prevesion_quantity(request,pf['default_code'],date_pr.year,date_pr.month)

        if par.capacite_prod:
            prevision_avrg = get_capacite_prod(request,pf['default_code'],date_pr.year)
            prd_ecart = stock_init-prevision_avrg
        else:
            prevision_avrg = prevesion_moyenne(pf['default_code'],date_pr.year)
            prd_ecart = stock_init-prd_min

        
        prd_can_prd_max = can_prd_global_IMP(prd_id,request)
        
        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,
                            'capacite':prevision_avrg,
                        }
        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 get_poles(code):
    data = []
    x = 0
    if code.startswith("BDM2"):
        date = code.split('-')
        x = int(date[1][0])
    if code.startswith("C"):
        date = code.split(' ')
        x = int(date[0].replace('C',''))
    if code.startswith("MD"):
        date = code.split(' ')
        x = int(date[0].replace('MD',''))
    #print(code,x)
    if x==1:
        return 1
    if x==2:
        return 2.5
    if x==3:
        return 3.5
    if x==4:
        return 5
    return 0

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)
    
    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']
        if par.capacite_prod:
            prd_min = get_capacite_prod(request,pf['default_code'],date_pr.year)
        else:
            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'])
        unipolaire = 0
        if pf['marque_id'][1]== 'disjoncteur magnetothermique':
            #print(pf['marque_id'],get_poles(pf['default_code']))
            unipolaire = productions*get_poles(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,
                        'prd_1p':unipolaire,
                    }
        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 = {}
Lead_time_G = {}
Month_global = {}
Month_title_global = {}

Needs_global = {}

Plan_charement_G = {}
Types_namesCMD_G = {}
Types_namesCHRG_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 = {}

Stock_prevue_G = {}
Stock_prevue_Month_G = {}

Stock_prevue_CMD_G = {}
Stock_prevue_CMD_Month_G = {}

categories_SIMUL_dic = {}
categories_CMD_dic = {}
stock_pf_simulation_dic = {}
stock_pf_commande_dic = {}
def Simulation_Chargement_calcule_V2(request):

    #print('jours resant',Get_Days_Remaining())
    
    form = ArticleFilterForm(request.GET or None)
    selected_id_sp = []
    Nbr_month = 0
    Transit_time = 0
    stock_pf_simulation = None
    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)
        stock_pf_simul = request.POST.get('stock_pf')
        if stock_pf_simul == 'true':
            stock_pf_simulation = True
        if stock_pf_simul == 'false':
            stock_pf_simulation = False
        stock_pf_simulation_dic[request.user.username] =stock_pf_simulation
        print('stock_pf_simul from poste',stock_pf_simulation)
        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

    print('stock_pf_simul local',stock_pf_simulation)
    print('stock_pf_simu global',stock_pf_simulation_dic[request.user.username])
        
    #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])
    
    
    Compoents_stock_dic = {}
    Compoents_forcast_dic = {}
    Assembie_compoents_dic = {}
    Categ_compoents = []
    for art_prd in result_prd_filtre_simult_dic[request.user.username]:

        # Stock du produit fini
        if stock_pf_simulation_dic[request.user.username]:
            stock_pf = art_prd['virtual_available']
            if stock_pf <= 0:
                stock_pf = 0
        else:
            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():
            #print('cid',cid)
            prd = get_product(cid, request)[0]
            code = prd['default_code']
            qty = info['qty']  # quantité calculée dans ta fonction
            val = prd['categ_id'][1]

            # Supprimer les espaces autour et découper par "/"
            parts = [p.strip() for p in val.split('/')]
            

            Categ_compoents = list(set(Categ_compoents + [parts[-1]]))
            # 👉 Si composant jamais ajouté → on l'ajoute
            if code not in Compoents_stock_dic:
                Compoents_stock_dic[code] = {
                    'idprd': cid,
                    'code': code,
                    'name': prd['name'],
                    'stock': qty,   # quantité initiale
                    'sale_ok': prd['sale_ok'],
                    'purchase_ok': prd['purchase_ok'],
                    'categ_id': parts[-1],
                    'virtual_available': prd['virtual_available'],
                    'inhand':Get_InHandByCode(request,code),
                }

            else:
                # 👉 Composant présent → on cumule les quantités
                Compoents_stock_dic[code]['stock'] += qty
            #if code == 'L066':
                #print('Sock PF',stock_pf,'qty',qty,'stock PF to MP',Compoents_stock_dic[code]['stock'])

        

        # GET SF COMPOENTS
        componet_subassemblies = get_subassemblies_with_bom(Boms_dic[request.user.username],Bom_Lines_dic[request.user.username],int(art_prd['bom_id']))
        for cidsf, infosf in componet_subassemblies.items():
            Assembie_compoents_dic[cidsf] = infosf['bom_id']
        

        # 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
            if request.session.get('capacite_prod', ''):
                qty_prv = get_capacite_prod(request,art_prd['default_code'],curent_date.year)
            else:
                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)
            

            month = curent_date.strftime("%B")
            month_chrg = 'chrg'+curent_date.strftime("%B")
            date_end_charg = date(curent_date.year,curent_date.month,15)
            date_start_charg = date_end_charg - relativedelta(months=1)
            #print('sataet bdate',date_start_charg,'end bdate',date_end_charg)
            # 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 cidfc, infofc in componet_pf_forcast.items():
                #print("line dic :",cid,',',info['name'],',', info['qty'])
                prdfc = get_product(cidfc,request)[0]
                codefc = prdfc['default_code']
                
                f_qty = infofc['qty']

                

                # Si nouveau composant → on crée l'entrée
                if codefc not in Compoents_forcast_dic:
                    Compoents_forcast_dic[codefc] = {}

                # Si mois non créé → on initialise
                if month not in Compoents_forcast_dic[codefc]:
                    Compoents_forcast_dic[codefc][month] = 0
                    Compoents_forcast_dic[codefc][month_chrg] = Get_ChargementByCode_V3(request, Transit_time_G[request.user.username],codefc,date_start_charg,date_end_charg)

                # On cumule la quantité forecast
                Compoents_forcast_dic[codefc][month] += f_qty
    #print('********************PF TO CMP STOCK BEFOR SF********************')
    #print(Compoents_stock_dic)
    #print('*******************************************************')
    #print(Categ_compoents)
    # SF stock to  to CMP stock
    for key, value in Assembie_compoents_dic.items():
       
            prdsfmp = get_product(key, request)[0]
            
            stock_sf = prdsfmp['virtual_available']
            if stock_sf < 0:
                stock_sf = 0
            
            componet_sf = get_all_components_by_bom(
            Boms_dic[request.user.username],
            Bom_Lines_dic[request.user.username],
            int(value),
            stock_sf)

            for cidmp, infomp in componet_sf.items():
                prdmp = get_product(cidmp, request)[0]
                codemp = prdmp['default_code']
                qtymp = infomp['qty'] 
                Compoents_stock_dic[codemp]['stock'] += qtymp
       
    #print('********************PF TO CMP STOCK global********************')
    #print(Compoents_stock_dic)
    #print('*******************************************************')
    # print('********************PF TO CMP FORCAST********************')
    # print(Compoents_forcast_dic)
    # print('*******************************************************')

    #print('********************SF TO CMP Stock AFTER********************')
    #print(Assembie_compoents_dic)
    #print('*******************************************************')
    

    # calcule stock prevue des composants par mois
    componet_dic = {}
    tableau = []
    months = []
    months_ETD = {}
    date_prevue_start = date.today()

    #print("code","mois","stock" "init","chargement","forcast","stockprevue","date1","date2")
    cpt = 1
    for code, data in Compoents_stock_dic.items():
        stock_global = data['stock'] + data['virtual_available']
        stock_remaing = stock_global
        
        row = {
                'idprd': data['idprd'],
                'article': code,
                'nom': data['name'],
                'stock': stock_global,
                'categ_id': data['categ_id'],
                'purchase_ok':data['purchase_ok'],
                'inhand':data['inhand'],
            }
        
        componet_dic[code] = row
        date_repture = None
        date_repture_init = None
        date_elm = {}
        iddate = 0
        for i in range(1, nbr_month_global[request.user.username]+1):
            curent_date = date_prevue_start +  relativedelta(months=i-1)
            month = curent_date.strftime("%B")
            date_etd = curent_date - timedelta(days=Transit_time_G[request.user.username])
            month_etd = date_etd.strftime("%B")
            if cpt ==1 :
              months.append(month)
              months_ETD[month]=month_etd
            month_chrg = 'chrg'+curent_date.strftime("%B")
            
            stock_remaing += Compoents_forcast_dic[code][month_chrg]

            stockfff = stock_remaing
            stock_prevue = stock_remaing   - Compoents_forcast_dic[code][month]
            stock_remaing -= Compoents_forcast_dic[code][month]
            if stock_remaing < 0 :
                stock_remaing = 0
                
            if stockfff < Compoents_forcast_dic[code][month] and  stockfff>0 :
                iddate+=1
                if i==1:
                    jours_restant = Compoents_forcast_dic[code][month]/jours_ouvrables_restants()
                else:
                    jours_restant = Compoents_forcast_dic[code][month]/22
                forcast_days = int(stockfff/jours_restant)
                
                if forcast_days < 1:
                    if i==1:
                      forcast_days =   date_prevue_start.day
                    else:
                        forcast_days = 1
                
                date_repture_init = date(curent_date.year, curent_date.month, forcast_days)
                if i == 1:
                    if date_repture_init.weekday()==4:
                        date_repture = date_repture_init + timedelta(days=2)
                    elif date_repture_init.weekday()==5:
                        date_repture = date_repture_init + timedelta(days=2)
                    else:
                        date_repture = date_repture_init
                else:
                    date_repture = date_repture_init + timedelta(days=count_weekend_days(date_repture_init))
                if code == 'MDACC363':
                    print('mois','cide','forcast','pre jour','stock init','nbr jour','dd','add days','df')
                    print(i,code,Compoents_forcast_dic[code][month],jours_restant,stockfff,forcast_days,date_repture_init,count_weekend_days(date_repture_init),date_repture)
                date_elm[iddate] = date_repture.strftime("%d/%m/%Y")
                #dates[code] = date_elm
                #date_repture = date(curent_date.year, curent_date.month, forcast_days+count_weekend_days(date_repture_init))
            #print(code,month,stockfff,Compoents_forcast_dic[code][month_chrg],Compoents_forcast_dic[code][month],stock_prevue,date_repture_init,date_repture)
            
            row[month] = stock_prevue
        if date_elm:
            row['date'] = date_elm[1]

            
        else:
            row['date'] = ''
        tableau.append(row)
        #print(date_elm)
        cpt =0
    if form.is_valid():
        categs = request.GET.getlist("categoreis")
        #print('Cats:',categs)
        tableau = [art for art in tableau if art['categ_id'] in categs] 

    tableau = sorted(tableau, key=lambda x: x['article'])
    Stock_prevue_G [request.user.username] =    tableau
    Stock_prevue_Month_G[request.user.username] =months
    Stock_prevue_Month__ETD_G[request.user.username] =months_ETD
    categories_SIMUL_dic[request.user.username] = Categ_compoents
    #print(tableau)
    #tableau = []


    context = {
        'months': Stock_prevue_Month_G[request.user.username],
        'products' :  Stock_prevue_G [request.user.username],
        'access':get_access(request.user.username),
        'Categories':sorted(categories_SIMUL_dic[request.user.username])
        
        #'nbr_result':len(result_simulation_planification),
        }

    return render(request,'planification_chargement.html',context)


Stock_prevue_Month__ETD_G = {}

def Simulation_Commande_calcule(request):

    #print('jours resant',Get_Days_Remaining())
    
    form = ArticleFilterForm(request.GET or None)
    selected_id_sp = []
    Nbr_month = 0
    Transit_time = 0
    stock_pf_CMD = None
    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)
        stock_pf_simul = request.POST.get('stock_pf')
        if stock_pf_simul == 'true':
            stock_pf_CMD = True

        
        if stock_pf_simul == 'false':
            stock_pf_CMD = False
        
        stock_pf_commande_dic[request.user.username] = stock_pf_CMD

        print('stock_pf_CMD POST', stock_pf_CMD)

        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)
        Lead_time_str = request.POST.get('Lead_time')
        if Transit_time_str and Transit_time_str.strip().isdigit():
            Transit_time = int(Transit_time_str)
            Lead_time_G[request.user.username] = Transit_time
        else:
            Transit_time = 90  # ou 0, selon ton besoin

        Lead_time_G[request.user.username] +=int(Lead_time_str)

    print('stock_pf_CMD GET', stock_pf_CMD)
    print('stock_pf_CMD global', stock_pf_commande_dic[request.user.username])
    #Nbr_months = Nbr_month - 1

    global result_prd_filtre_simultCMD_dic

    #Articles_PF_dic[request.user.username]
    global Bom_Lines
    result_simulation_planification = []
    
    #print(selected_id_sp)    
    for rp in result_prd_filtre_simultCMD_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])
    
    
    Compoents_stockCMD_dic = {}
    Compoents_forcastCMD_dic = {}
    Assembie_compoentsCMD_dic = {}
    Categ_compoents_cmd = []
    for art_prd in result_prd_filtre_simultCMD_dic[request.user.username]:

        # Stock du produit fini
        print('stock_pf_CMD',stock_pf_commande_dic[request.user.username])
        if stock_pf_commande_dic[request.user.username]:
            stock_pf = art_prd['virtual_available']
            print('stock_pf before ',stock_pf)
            if stock_pf <= 0:
                stock_pf = 0
            print('stock_pf 2',stock_pf)
        else:
            stock_pf = 0
        print('stock_pf after',stock_pf)
        # Récupération des composants de PF
        componet_cmd_pf = get_all_components_by_bom2(
            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_cmd_pf.items():
            #print('cid',cid)
            prd = get_product(cid, request)[0]
            code = prd['default_code']
            qty = info['qty']  # quantité calculée dans ta fonction
            val = prd['categ_id'][1]

            # Supprimer les espaces autour et découper par "/"
            parts = [p.strip() for p in val.split('/')]
            

            
            # 👉 Si composant jamais ajouté → on l'ajoute
            if code not in Compoents_stockCMD_dic:
                Compoents_stockCMD_dic[code] = {
                    'idprd': cid,
                    'code': code,
                    'name': prd['name'],
                    'stock': qty,   # quantité initiale
                    'sale_ok': prd['sale_ok'],
                    'purchase_ok': prd['purchase_ok'],
                    'categ_id': parts[-1],
                    'virtual_available': prd['virtual_available'],
                    'inhand':Get_InHandByCode(request,code),
                    'chargement':Get_ChargementByCode_V4(request,code),
                    'commande':Achats_local_dic[request.user.username].get(cid, 0),
                }

            else:
                # 👉 Composant présent → on cumule les quantités
                Compoents_stockCMD_dic[code]['stock'] += qty
            #if code == 'L066':
                #print('Sock PF',stock_pf,'qty',qty,'stock PF to MP',Compoents_stockCMD_dic[code]['stock'])

        

        # GET SF COMPOENTS
        componetCMD_subassemblies = get_subassemblies_with_bom(Boms_dic[request.user.username],Bom_Lines_dic[request.user.username],int(art_prd['bom_id']))
        for cidsf, infosf in componetCMD_subassemblies.items():
            Assembie_compoentsCMD_dic[cidsf] = infosf['bom_id']
        

        # PF previon by month to cmp previson by month
        date_prevue_start = date.today()
        date_start_lead = date_prevue_start + timedelta(days=Lead_time_G[request.user.username])
        date_end_lead = date_start_lead +  relativedelta(months=nbr_month_global[request.user.username]-1)
        while date_prevue_start <= date_end_lead :

            if request.session.get('capacite_prod', ''):
                qty_prv = get_capacite_prod(request,art_prd['default_code'],date_prevue_start.year)
            else:
                qty_prv = get_prevesion_quantity(request,art_prd['default_code'],date_prevue_start.year,date_prevue_start.month)

            # if the frist month calcule the remainig days of sales
            if date_prevue_start.month ==date.today().month:
                #print('days left',jours_ouvrables_restants())
                qty_prv = int(qty_prv/22*jours_ouvrables_restants())

            month = date_prevue_start.strftime("%B-%Y").capitalize()
            
            
            
            #print('sataet bdate',date_start_charg,'end bdate',date_end_charg)
            # get all compoents for forcast

            componet_pfCMD_forcast = get_all_components_by_bom2(Boms_dic[request.user.username], Bom_Lines_dic[request.user.username], int(art_prd['bom_id']),qty_prv)
            for cidfc, infofc in componet_pfCMD_forcast.items():
                #print("line dic :",cid,',',info['name'],',', info['qty'])
                prdfc = get_product(cidfc,request)[0]
                codefc = prdfc['default_code']
                
                f_qty = infofc['qty']

                

                # Si nouveau composant → on crée l'entrée
                if codefc not in Compoents_forcastCMD_dic:
                    Compoents_forcastCMD_dic[codefc] = {}

                # Si mois non créé → on initialise
                if month not in Compoents_forcastCMD_dic[codefc]:
                    Compoents_forcastCMD_dic[codefc][month] = 0
                    

                # On cumule la quantité forecast
                Compoents_forcastCMD_dic[codefc][month] += f_qty




            date_prevue_start += relativedelta(months=1)
    

    

        """ 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
            if request.session.get('capacite_prod', ''):
                qty_prv = get_capacite_prod(request,art_prd['default_code'],curent_date.year)
            else:
                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)
            

            month = curent_date.strftime("%B")
            month_chrg = 'chrg'+curent_date.strftime("%B")
            
            
            #print('sataet bdate',date_start_charg,'end bdate',date_end_charg)
            # get all compoents for forcast

            componet_pfCMD_forcast = get_all_components_by_bom2(Boms_dic[request.user.username], Bom_Lines_dic[request.user.username], int(art_prd['bom_id']),qty_prv)
            for cidfc, infofc in componet_pfCMD_forcast.items():
                #print("line dic :",cid,',',info['name'],',', info['qty'])
                prdfc = get_product(cidfc,request)[0]
                codefc = prdfc['default_code']
                
                f_qty = infofc['qty']

                

                # Si nouveau composant → on crée l'entrée
                if codefc not in Compoents_forcastCMD_dic:
                    Compoents_forcastCMD_dic[codefc] = {}

                # Si mois non créé → on initialise
                if month not in Compoents_forcastCMD_dic[codefc]:
                    Compoents_forcastCMD_dic[codefc][month] = 0
                    

                # On cumule la quantité forecast
                Compoents_forcastCMD_dic[codefc][month] += f_qty """
    #print('********************PF TO CMP STOCK BEFOR SF********************')
    #print(Compoents_stockCMD_dic)
    #print('*******************************************************')
    #print(Categ_compoents)
    #print('forcast',Compoents_forcastCMD_dic)
    # SF stock to  to CMP stock
    for key, value in Assembie_compoentsCMD_dic.items():
       
            prdsfmp = get_product(key, request)[0]
            
            stock_sf = prdsfmp['virtual_available']
            if stock_sf < 0:
                stock_sf = 0
            
            componet_sf = get_all_components_by_bom2(
            Boms_dic[request.user.username],
            Bom_Lines_dic[request.user.username],
            int(value),
            stock_sf)

            for cidmp, infomp in componet_sf.items():
                prdmp = get_product(cidmp, request)[0]
                codemp = prdmp['default_code']
                qtymp = infomp['qty'] 
                Compoents_stockCMD_dic[codemp]['stock'] += qtymp
       
    #print('********************PF TO CMP STOCK global********************')
    #print(Compoents_stockCMD_dic)
    #print('*******************************************************')
    # print('********************PF TO CMP FORCAST********************')
    # print(Compoents_forcastCMD_dic)
    # print('*******************************************************')

    #print('********************SF TO CMP Stock AFTER********************')
    #print(Assembie_compoentsCMD_dic)
    #print('*******************************************************')
    

    # calcule stock prevue des composants par mois
    
    tableauCMD = []
    months_cmd = []
    date_prevue_start = date.today()

    #print("code","mois","stock" "init","chargement","forcast","stockprevue","date1","date2")
    cpt = 1
    for code, data in Compoents_stockCMD_dic.items():
        stock_global = data['stock'] + data['virtual_available']+data['inhand'] + data['chargement']+data['commande'] 
        stock_remaing = stock_global
        
        row = {
                'idprd': data['idprd'],
                'article': code,
                'nom': data['name'],
                'stock': stock_global,
                'categ_id': data['categ_id'],
                'purchase_ok':data['purchase_ok']
            }
        
        date_repture = None
        date_repture_init = None
        date_elm = {}
        iddate = 0

        date_prevue_start = date.today()
        while date_prevue_start <= date_end_lead :
            
            month = date_prevue_start.strftime("%B-%Y").capitalize()
            if cpt ==1 :
              months_cmd.append(month)
           
            stockfff = stock_remaing
            stock_prevue = stock_remaing   - Compoents_forcastCMD_dic[code][month]
            stock_remaing -= Compoents_forcastCMD_dic[code][month]
            if stock_remaing < 0 :
                stock_remaing = 0
                
            if stockfff < Compoents_forcastCMD_dic[code][month] and  stockfff>0 :
                iddate+=1
                if date_prevue_start.month==date.today().month:
                    jours_restant = Compoents_forcastCMD_dic[code][month]/jours_ouvrables_restants()
                else:
                    jours_restant = Compoents_forcastCMD_dic[code][month]/22
                forcast_days = int(stockfff/jours_restant)
                
                if forcast_days < 1:
                    if date_prevue_start.month==date.today().month:
                      forcast_days =   date_prevue_start.day
                    else:
                        forcast_days = 1
                
                date_repture_init = date(date_prevue_start.year, date_prevue_start.month, forcast_days)
                if date_prevue_start.month==date.today().month:
                    if date_repture_init.weekday()==4:
                        date_repture = date_repture_init + timedelta(days=2)
                    elif date_repture_init.weekday()==5:
                        date_repture = date_repture_init + timedelta(days=2)
                    else:
                        date_repture = date_repture_init
                else:
                    date_repture = date_repture_init + timedelta(days=count_weekend_days(date_repture_init))
                # if code == 'MDACC363':
                #     print('mois','cide','forcast','pre jour','stock init','nbr jour','dd','add days','df')
                #     print(i,code,Compoents_forcastCMD_dic[code][month],jours_restant,stockfff,forcast_days,date_repture_init,count_weekend_days(date_repture_init),date_repture)
                date_elm[iddate] = date_repture.strftime("%d/%m/%Y")
                #dates[code] = date_elm
                #date_repture = date(curent_date.year, curent_date.month, forcast_days+count_weekend_days(date_repture_init))
            #print(code,month,stockfff,Compoents_forcastCMD_dic[code][month_chrg],Compoents_forcastCMD_dic[code][month],stock_prevue,date_repture_init,date_repture)


            date_prevue_start += relativedelta(months=1)

        # for i in range(1, nbr_month_global[request.user.username]+1):
        #     curent_date = date_prevue_start +  relativedelta(months=i-1)
        #     month = curent_date.strftime("%B-%Y").capitalize()
        #     if cpt ==1 :
        #       months_cmd.append(month)
           
        #     stockfff = stock_remaing
        #     stock_prevue = stock_remaing   - Compoents_forcastCMD_dic[code][month]
        #     stock_remaing -= Compoents_forcastCMD_dic[code][month]
        #     if stock_remaing < 0 :
        #         stock_remaing = 0
                
        #     if stockfff < Compoents_forcastCMD_dic[code][month] and  stockfff>0 :
        #         iddate+=1
        #         if i==1:
        #             jours_restant = Compoents_forcastCMD_dic[code][month]/jours_ouvrables_restants()
        #         else:
        #             jours_restant = Compoents_forcastCMD_dic[code][month]/22
        #         forcast_days = int(stockfff/jours_restant)
                
        #         if forcast_days < 1:
        #             if i==1:
        #               forcast_days =   date_prevue_start.day
        #             else:
        #                 forcast_days = 1
                
        #         date_repture_init = date(curent_date.year, curent_date.month, forcast_days)
        #         if i == 1:
        #             if date_repture_init.weekday()==4:
        #                 date_repture = date_repture_init + timedelta(days=2)
        #             elif date_repture_init.weekday()==5:
        #                 date_repture = date_repture_init + timedelta(days=2)
        #             else:
        #                 date_repture = date_repture_init
        #         else:
        #             date_repture = date_repture_init + timedelta(days=count_weekend_days(date_repture_init))
        #         # if code == 'MDACC363':
        #         #     print('mois','cide','forcast','pre jour','stock init','nbr jour','dd','add days','df')
        #         #     print(i,code,Compoents_forcastCMD_dic[code][month],jours_restant,stockfff,forcast_days,date_repture_init,count_weekend_days(date_repture_init),date_repture)
        #         date_elm[iddate] = date_repture.strftime("%d/%m/%Y")
        #         #dates[code] = date_elm
        #         #date_repture = date(curent_date.year, curent_date.month, forcast_days+count_weekend_days(date_repture_init))
        #     #print(code,month,stockfff,Compoents_forcastCMD_dic[code][month_chrg],Compoents_forcastCMD_dic[code][month],stock_prevue,date_repture_init,date_repture)
            
            row[month] = stock_prevue
        if date_elm:
            row['date'] = date_elm[1]
            tableauCMD.append(row)
        
        #print(date_elm)
        cpt =0
    
    #print(tableauCMD)

    Needs_CMD = []
    
    for sp in tableauCMD:
        x = {}
        x['article'] = sp['article']
        x['nom'] = sp['nom']
        x['date'] = sp['date']
        x['categ_id'] = sp['categ_id']
        
        x['purchase_ok'] = sp['purchase_ok']
        if sp['purchase_ok']:
            if sp['article'].startswith('L'):
               x['type']= 'Achats Local'
            else:
                x['type']= 'Achats Importation'
        
        besoin_cmd = 0
        for m in months_cmd:
            if sp['purchase_ok']:
                if sp[m] >= 0:
                    x[m] = 0
                else:
                    x[m] =  abs(sp[m])
                    
                besoin_cmd+= x[m]
        if besoin_cmd> 0 :
            Categ_compoents_cmd = list(set(Categ_compoents_cmd + [sp['categ_id']]))
            x['besoin_cmd'] = besoin_cmd
            Needs_CMD.append(x)

    Month_not_zero = []
    for m in months_cmd:
    # On vérifie si TOUTES les lignes ont une valeur différente de 0 pour ce mois
        if any(item[m] != 0 for item in Needs_CMD):
            Month_not_zero.append(m)

    print(Month_not_zero)

    types_name = list({d["type"] for d in Needs_CMD})
    #tableauCMD = []
    if form.is_valid():
        categs_cmd = request.GET.getlist("categoreis")
        types_cmd = request.GET.getlist("types")
        #print('Cats:',categs)
        if categs_cmd :
            Needs_CMD = [art for art in Needs_CMD if art['categ_id'] in categs_cmd] 
        if types_cmd :
            Needs_CMD = [art for art in Needs_CMD if art['type'] in types_cmd]

    Needs_CMD = sorted(Needs_CMD, key=lambda x: x['article'])
    Stock_prevue_CMD_G [request.user.username] =    Needs_CMD
    Stock_prevue_CMD_Month_G[request.user.username] =Month_not_zero
    categories_CMD_dic[request.user.username] = Categ_compoents_cmd
    #print(tableauCMD)
    #tableauCMD = []

    Types_namesCMD_G[request.user.username] =types_name
    context = {
        'months': Stock_prevue_CMD_Month_G[request.user.username],
        'products' :  Stock_prevue_CMD_G [request.user.username],
        'access':get_access(request.user.username),
        'Categories':sorted(categories_CMD_dic[request.user.username]),
        'types':Types_namesCMD_G[request.user.username] 
        #'nbr_result':len(result_simulation_planification),
        }

    return render(request,'planification_commande.html',context)


def Simulation_Commande_calcule_org(request):

    #print('jours resant',Get_Days_Remaining())
    
    form = ArticleFilterForm(request.GET or None)
    selected_id_sp = []
    Nbr_month = 0
    Transit_time = 0
    stock_pf_CMD = False
    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)
        stock_pf_simul = request.POST.get('stock_pf')
        if stock_pf_simul == 'true':
            stock_pf_CMD = True
        if stock_pf_simul == 'false':
            stock_pf_CMD = False

        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)
        Lead_time_str = request.POST.get('Transit_time')
        if Transit_time_str and Transit_time_str.strip().isdigit():
            Transit_time = int(Transit_time_str)
            Lead_time_G[request.user.username] = Transit_time
        else:
            Transit_time = 90  # ou 0, selon ton besoin

        Lead_time_G[request.user.username] +=int(Lead_time_str)


    #Nbr_months = Nbr_month - 1

    global result_prd_filtre_simultCMD_dic

    #Articles_PF_dic[request.user.username]
    global Bom_Lines
    result_simulation_planification = []
    
    #print(selected_id_sp)    
    for rp in result_prd_filtre_simultCMD_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])
    
    
    Compoents_stockCMD_dic = {}
    Compoents_forcastCMD_dic = {}
    Assembie_compoentsCMD_dic = {}
    Categ_compoents_cmd = []
    for art_prd in result_prd_filtre_simultCMD_dic[request.user.username]:

        # Stock du produit fini
        if stock_pf_CMD:
            stock_pf = art_prd['virtual_available']
            if stock_pf <= 0:
                stock_pf = 0
        else:
            stock_pf = 0

        # Récupération des composants de PF
        componet_cmd_pf = get_all_components_by_bom2(
            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_cmd_pf.items():
            #print('cid',cid)
            prd = get_product(cid, request)[0]
            code = prd['default_code']
            qty = info['qty']  # quantité calculée dans ta fonction
            val = prd['categ_id'][1]

            # Supprimer les espaces autour et découper par "/"
            parts = [p.strip() for p in val.split('/')]
            

            
            # 👉 Si composant jamais ajouté → on l'ajoute
            if code not in Compoents_stockCMD_dic:
                Compoents_stockCMD_dic[code] = {
                    'idprd': cid,
                    'code': code,
                    'name': prd['name'],
                    'stock': qty,   # quantité initiale
                    'sale_ok': prd['sale_ok'],
                    'purchase_ok': prd['purchase_ok'],
                    'categ_id': parts[-1],
                    'virtual_available': prd['virtual_available'],
                    'inhand':Get_InHandByCode(request,code),
                    'chargement':Get_ChargementByCode_V4(request,code),
                    'commande':Achats_local_dic[request.user.username].get(cid, 0),
                }

            else:
                # 👉 Composant présent → on cumule les quantités
                Compoents_stockCMD_dic[code]['stock'] += qty
            #if code == 'L066':
                #print('Sock PF',stock_pf,'qty',qty,'stock PF to MP',Compoents_stockCMD_dic[code]['stock'])

        

        # GET SF COMPOENTS
        componetCMD_subassemblies = get_subassemblies_with_bom(Boms_dic[request.user.username],Bom_Lines_dic[request.user.username],int(art_prd['bom_id']))
        for cidsf, infosf in componetCMD_subassemblies.items():
            Assembie_compoentsCMD_dic[cidsf] = infosf['bom_id']
        

        # 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
            if request.session.get('capacite_prod', ''):
                qty_prv = get_capacite_prod(request,art_prd['default_code'],curent_date.year)
            else:
                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)
            

            month = curent_date.strftime("%B")
            month_chrg = 'chrg'+curent_date.strftime("%B")
            
            
            #print('sataet bdate',date_start_charg,'end bdate',date_end_charg)
            # get all compoents for forcast

            componet_pfCMD_forcast = get_all_components_by_bom2(Boms_dic[request.user.username], Bom_Lines_dic[request.user.username], int(art_prd['bom_id']),qty_prv)
            for cidfc, infofc in componet_pfCMD_forcast.items():
                #print("line dic :",cid,',',info['name'],',', info['qty'])
                prdfc = get_product(cidfc,request)[0]
                codefc = prdfc['default_code']
                
                f_qty = infofc['qty']

                

                # Si nouveau composant → on crée l'entrée
                if codefc not in Compoents_forcastCMD_dic:
                    Compoents_forcastCMD_dic[codefc] = {}

                # Si mois non créé → on initialise
                if month not in Compoents_forcastCMD_dic[codefc]:
                    Compoents_forcastCMD_dic[codefc][month] = 0
                    

                # On cumule la quantité forecast
                Compoents_forcastCMD_dic[codefc][month] += f_qty
    #print('********************PF TO CMP STOCK BEFOR SF********************')
    #print(Compoents_stockCMD_dic)
    #print('*******************************************************')
    #print(Categ_compoents)

    # SF stock to  to CMP stock
    for key, value in Assembie_compoentsCMD_dic.items():
       
            prdsfmp = get_product(key, request)[0]
            
            stock_sf = prdsfmp['virtual_available']
            if stock_sf < 0:
                stock_sf = 0
            
            componet_sf = get_all_components_by_bom2(
            Boms_dic[request.user.username],
            Bom_Lines_dic[request.user.username],
            int(value),
            stock_sf)

            for cidmp, infomp in componet_sf.items():
                prdmp = get_product(cidmp, request)[0]
                codemp = prdmp['default_code']
                qtymp = infomp['qty'] 
                Compoents_stockCMD_dic[codemp]['stock'] += qtymp
       
    #print('********************PF TO CMP STOCK global********************')
    #print(Compoents_stockCMD_dic)
    #print('*******************************************************')
    # print('********************PF TO CMP FORCAST********************')
    # print(Compoents_forcastCMD_dic)
    # print('*******************************************************')

    #print('********************SF TO CMP Stock AFTER********************')
    #print(Assembie_compoentsCMD_dic)
    #print('*******************************************************')
    

    # calcule stock prevue des composants par mois
    
    tableauCMD = []
    months_cmd = []
    date_prevue_start = date.today()

    #print("code","mois","stock" "init","chargement","forcast","stockprevue","date1","date2")
    cpt = 1
    for code, data in Compoents_stockCMD_dic.items():
        stock_global = data['stock'] + data['virtual_available']+data['inhand'] + data['chargement']+data['commande'] 
        stock_remaing = stock_global
        
        row = {
                'idprd': data['idprd'],
                'article': code,
                'nom': data['name'],
                'stock': stock_global,
                'categ_id': data['categ_id'],
                'purchase_ok':data['purchase_ok']
            }
        
        date_repture = None
        date_repture_init = None
        date_elm = {}
        iddate = 0
        for i in range(1, nbr_month_global[request.user.username]+1):
            curent_date = date_prevue_start +  relativedelta(months=i-1)
            month = curent_date.strftime("%B")
            if cpt ==1 :
              months_cmd.append(month)
           
            stockfff = stock_remaing
            stock_prevue = stock_remaing   - Compoents_forcastCMD_dic[code][month]
            stock_remaing -= Compoents_forcastCMD_dic[code][month]
            if stock_remaing < 0 :
                stock_remaing = 0
                
            if stockfff < Compoents_forcastCMD_dic[code][month] and  stockfff>0 :
                iddate+=1
                if i==1:
                    jours_restant = Compoents_forcastCMD_dic[code][month]/jours_ouvrables_restants()
                else:
                    jours_restant = Compoents_forcastCMD_dic[code][month]/22
                forcast_days = int(stockfff/jours_restant)
                
                if forcast_days < 1:
                    if i==1:
                      forcast_days =   date_prevue_start.day
                    else:
                        forcast_days = 1
                
                date_repture_init = date(curent_date.year, curent_date.month, forcast_days)
                if i == 1:
                    if date_repture_init.weekday()==4:
                        date_repture = date_repture_init + timedelta(days=2)
                    elif date_repture_init.weekday()==5:
                        date_repture = date_repture_init + timedelta(days=2)
                    else:
                        date_repture = date_repture_init
                else:
                    date_repture = date_repture_init + timedelta(days=count_weekend_days(date_repture_init))
                # if code == 'MDACC363':
                #     print('mois','cide','forcast','pre jour','stock init','nbr jour','dd','add days','df')
                #     print(i,code,Compoents_forcastCMD_dic[code][month],jours_restant,stockfff,forcast_days,date_repture_init,count_weekend_days(date_repture_init),date_repture)
                date_elm[iddate] = date_repture.strftime("%d/%m/%Y")
                #dates[code] = date_elm
                #date_repture = date(curent_date.year, curent_date.month, forcast_days+count_weekend_days(date_repture_init))
            #print(code,month,stockfff,Compoents_forcastCMD_dic[code][month_chrg],Compoents_forcastCMD_dic[code][month],stock_prevue,date_repture_init,date_repture)
            
            row[month] = stock_prevue
        if date_elm:
            row['date'] = date_elm[1]
            tableauCMD.append(row)
        
        #print(date_elm)
        cpt =0
    
    #print(tableauCMD)

    Needs_CMD = []
    
    for sp in tableauCMD:
        x = {}
        x['article'] = sp['article']
        x['nom'] = sp['nom']
        x['date'] = sp['date']
        x['categ_id'] = sp['categ_id']
        
        x['purchase_ok'] = sp['purchase_ok']
        if sp['purchase_ok']:
            if sp['article'].startswith('L'):
               x['type']= 'Achats Local'
            else:
                x['type']= 'Achats Importation'
        
        besoin_cmd = 0
        for m in months_cmd:
            if sp['purchase_ok']:
                if sp[m] >= 0:
                    x[m] = 0
                else:
                    x[m] =  abs(sp[m])
                    
                besoin_cmd+= x[m]
        if besoin_cmd> 0 :
            Categ_compoents_cmd = list(set(Categ_compoents_cmd + [sp['categ_id']]))
            x['besoin_cmd'] = besoin_cmd
            Needs_CMD.append(x)

    Month_not_zero = []
    for m in months_cmd:
    # On vérifie si TOUTES les lignes ont une valeur différente de 0 pour ce mois
        if any(item[m] != 0 for item in Needs_CMD):
            Month_not_zero.append(m)

    print(Month_not_zero)

    types_name = list({d["type"] for d in Needs_CMD})
    #tableauCMD = []
    if form.is_valid():
        categs_cmd = request.GET.getlist("categoreis")
        types_cmd = request.GET.getlist("types")
        #print('Cats:',categs)
        if categs_cmd :
            Needs_CMD = [art for art in Needs_CMD if art['categ_id'] in categs_cmd] 
        if types_cmd :
            Needs_CMD = [art for art in Needs_CMD if art['type'] in types_cmd]

    Needs_CMD = sorted(Needs_CMD, key=lambda x: x['article'])
    Stock_prevue_CMD_G [request.user.username] =    Needs_CMD
    Stock_prevue_CMD_Month_G[request.user.username] =Month_not_zero
    categories_CMD_dic[request.user.username] = Categ_compoents_cmd
    #print(tableauCMD)
    #tableauCMD = []

    Types_namesCMD_G[request.user.username] =types_name
    context = {
        'months': Stock_prevue_CMD_Month_G[request.user.username],
        'products' :  Stock_prevue_CMD_G [request.user.username],
        'access':get_access(request.user.username),
        'Categories':sorted(categories_CMD_dic[request.user.username]),
        'types':Types_namesCMD_G[request.user.username] 
        #'nbr_result':len(result_simulation_planification),
        }

    return render(request,'planification_commande.html',context)

def Calcule_Besoin(request):
    form = ArticleFilterForm(request.GET or None)
    print('calcule besoin')
    Needs = []
    
    for sp in Stock_prevue_G [request.user.username]:
        x = {}
        x['article'] = sp['article']
        x['idprd'] = sp['idprd']
        x['nom'] = sp['nom']
        x['date'] = sp['date']
        x['categ_id'] = sp['categ_id']
        x['purchase_ok'] = sp['purchase_ok']
        x['inhand'] = sp['inhand']

        flag = 0
        for m in Stock_prevue_Month_G[request.user.username]:
            
            if sp[m] >= 0:
                x[m] = 0
            else:
                x[m] =  abs(sp[m])
                
                flag += 1
        if flag > 0 :
            Needs.append(x)

    if form.is_valid():
        categs = request.GET.getlist("categoreis")
        print('Cats:',categs)
        Needs = [art for art in Needs if art['categ_id'] in categs]

    Needs_global[request.user.username] = Needs
    context = {
        'months': Stock_prevue_Month_G[request.user.username],
        'products' : Needs_global[request.user.username],
        'access':get_access(request.user.username),
        'Categories':sorted(categories_SIMUL_dic[request.user.username])
        #'nbr_result':len(result_simulation_planification),
        }

    return render(request,'Besoin.html',context)

Month_style_G = {}
def Plan_Approu(request):
    Plan_charement = []
    month_style = []
    for sp in Needs_global [request.user.username]:
        x = {}
        x['article'] = sp['article']
        x['idprd'] = sp['idprd']
        x['nom'] = sp['nom']
        x['date'] = sp['date']
        x['categ_id'] = sp['categ_id']
        
        

        if sp['purchase_ok']:
            if sp['article'].startswith('L'):
               x['type']= 'Achats Local'
            else:
                x['type']= 'Achats Importation'
        else:
            x['type']= 'Manufacturing'
        

        if x['type'] == 'Achats Importation':
            x['inhand'] = sp['inhand']
        elif x['type'] == 'Manufacturing':
            x['inhand'] = Produces_local_dic[request.user.username].get(x['idprd'], 0)
        elif x['type'] == 'Achats Local':
            x['inhand'] = Achats_local_dic[request.user.username].get(x['idprd'], 0)

        stock_inti = x['inhand']
        val = False

        for m in Stock_prevue_Month_G[request.user.username]:
            x[m] = sp[m]
            besoin_m = sp[m]
            print()
            if Stock_prevue_Month__ETD_G[request.user.username][m]==Stock_prevue_Month_G[request.user.username][0]:
                val = True
            if besoin_m > 0:
                if stock_inti >= besoin_m:
                    stock_inti-=besoin_m
                    if val:
                        x[m+"ok"] = 1
                    else:
                        x[m+"ok"] = 2
                else:
                    stock_inti = 0
                    x[m+"ok"] = 0
            else:
                x[m+"ok"] = 1
        
        #print(x)
        Plan_charement.append(x)
    
    types_name = list({d["type"] for d in Plan_charement})
    form = ArticleFilterForm(request.GET or None)
    if form.is_valid():
        categs = request.GET.getlist("categoreis")
        types = request.GET.getlist("types")
        print('Cats:',categs)
        if categs:
            Plan_charement = [art for art in Plan_charement if art['categ_id'] in categs]
        if types :
            Plan_charement = [art for art in Plan_charement if art['type'] in types]

    Plan_charement_G[request.user.username] = Plan_charement
    

    Types_namesCHRG_G[request.user.username] =types_name



    Month_style_G[request.user.username] = [(m, f"{m}ok") for m in Stock_prevue_Month_G[request.user.username]]
    
    context = {
        'months': Month_style_G[request.user.username],
        'months_ETD':list(Stock_prevue_Month__ETD_G[request.user.username].values()),
        'products' : Plan_charement_G[request.user.username],
        'access':get_access(request.user.username),
        'Categories':sorted(categories_SIMUL_dic[request.user.username]),
        'types':Types_namesCHRG_G[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

from datetime import date, timedelta

def count_weekend_days(given_date):
    # 1) Premier jour du mois
    first_day = date(given_date.year, given_date.month, 1)

    # 2) Compteur global
    total = 0

    # 3) Parcours de toutes les dates
    d = first_day
    while d <= given_date:
        if d.weekday() in (4, 5):   # 4 = vendredi, 5 = samedi
            total += 1
        d += timedelta(days=1)

    return total



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_ChargementByCode_V2(request,month,transit_time,code):

    
    qs = Chargement.objects.annotate(date_eta= F('Etd') + timedelta(days=transit_time)
    ).filter(
        date_eta__month=month
    ).values('Num')

    

    nums = list(qs.values_list('Num', flat=True))

    

    qty = Chargement_lines.objects.filter(Num__in=result, Product=code)\
        .aggregate(Qty=Sum('Qty'))['Qty']

    return qty if qty else 0


def Get_ChargementByCode_V3(request, transit_time, code, dd, df):
    # Annoter la date cible
    chargements = Chargement.objects.annotate(
        date_cible=F('Etd') + timedelta(days=transit_time)
    ).filter(
        Q(date_cible__gte=dd) & Q(date_cible__lte=df), Etat__in=['Expédé', 'Arrivé']
    ).values_list('Num', flat=True)

    nums = list(chargements)

    # Calculer la somme des Qty
    qty = Chargement_lines.objects.filter(Num__in=nums, Product=code)\
        .aggregate(Qty=Sum('Qty'))['Qty']

    return qty if qty else 0


def Get_ChargementByCode_V4(request, code):
    qty = Chargement_lines.objects.filter(
        Product=code,
        Num__in=Chargement.objects.filter(Etat__in=['Expédé', 'Arrivé'])
    ).aggregate(total=Sum('Qty'))['total']

    return qty or 0



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 = {}
result_prd_filtre_simultCMD_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 Simulation_Commande(request):
    
    global result_prd_dic,Articles_PF_dic
    
    print('simulation commande')
    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_simultCMD_dic
    result_prd_filtre_simultCMD_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_simultCMD_dic[request.user.username],
        'nom':default_code,
        'boms':Boms_dic[request.user.username],
        'nbr_result':len(result_prd_filtre_simultCMD_dic[request.user.username]),
        'access':get_access(request.user.username),
        }
    
    
    return render(request,'simulation_commande.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