import os
import pdfkit
from itertools import product
from multiprocessing import Value

from django.conf import settings
from django.db.models import Case, When, Value, IntegerField, Q, BooleanField, F, Sum, Count,OuterRef, Subquery,CharField
from django.db.models.functions import Coalesce
from rest_framework.exceptions import ValidationError
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

from .scripts import update_price_master_from_sheet

from .models import OrderRequests, OrderRequestFiles, OrderHistory, BookedSlots, PriceMaster, CostCenter, OrderCharges, \
    Orders, OrderStatus, ExtraCharges, OffDays, TermsAndConditions, EmailLog, UnloadInstructions, OrderFiles, CustomerContacts, OrderPriceLink
from .serializers import OrderRequestSerializer, OrderRequestFileSerializer, get_product_id_by_name, \
    get_address_ids_by_query, get_allowed_loading_slots_for_product, get_available_transporters, \
    get_preferred_delivery_time, get_loading_datetime, OrderHistorySerializer, OrderSerializer, OrderDetailsSerializer, \
    OrderStatusSerializer, get_address_details_from_id, UpdateOrderStatusSerializer, OrderXMLSerializer, \
    convert_to_number, convert_to_belgium_format, get_previous_non_holiday, check_is_delivery_on_holiday, \
    ExtraChargeSerializer, LoadListSerializer, TransportMailSerializer, CustomerMailSerializer, CMRSerializer, \
    OrderRequestListSerializer, RequestListSerializer, is_date_a_holiday, get_alternate_product, get_costcenter_details, \
    LoadPlanSerializer, OrderXMLSerializerNew, PriceMasterSerializer, SimilarOrderInputSerializer, \
    ExtraChargeGeneralSerializer, get_address_with_id
from . import serializers as customer_serializer
import base64, uuid, mimetypes
from rest_framework.pagination import PageNumberPagination
from datetime import datetime, timedelta, date
from django.utils.timezone import now
from django.db import transaction
from datetime import datetime
from django.utils import timezone
from . import utils as purchase_utils
from . import serializers as purchase_serializer
from . import models as po_models
from . import fetch_data
from .services.erp_client import OdooAPIService

import xml.etree.ElementTree as ET
import io
import zipfile
from django.http import HttpResponse, JsonResponse
import requests
from django.http import FileResponse
from django.core.mail import EmailMessage
from django.db import connection
from django.utils.timezone import now
import re
from decimal import Decimal, ROUND_HALF_UP

from django.template.loader import get_template
# from xhtml2pdf import pisa
from collections import defaultdict
from django.core.files.base import ContentFile
from django.core.exceptions import ObjectDoesNotExist
from django.db import connections
from itertools import chain

# MIME type to file extension mapping
MIME_TO_EXTENSION = {
    'data:application/pdf': '.pdf',
    'data:image/jpeg': '.jpeg',
    'data:image/png': '.png',
    'data:image/gif': '.gif',
    'data:image/bmp': '.bmp',
    'data:image/tiff': '.tiff',
    'data:image/webp': '.webp',
    'data:text/plain': '.txt',
    'data:text/html': '.html',
    'data:application/json': '.json',
    'data:application/xml': '.xml',
    'data:application/msword': '.doc',
    'data:application/vnd.openxmlformats-officedocument.wordprocessingml.document': '.docx',
    'data:application/vnd.ms-excel': '.xls',
    'data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': '.xlsx',
    'data:application/vnd.ms-powerpoint': '.ppt',
    'data:application/vnd.openxmlformats-officedocument.presentationml.presentation': '.pptx',
    'data:audio/mpeg': '.mp3',
    'data:audio/wav': '.wav',
    'data:audio/ogg': '.ogg',
    'data:video/mp4': '.mp4',
    'data:application/zip': '.zip',
    'data:application/octet-stream': '.bin',  # For unknown or generic file types
}


import time
from functools import wraps

def measure_time(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start_time = time.time()  # Start timer
        result = func(*args, **kwargs)
        end_time = time.time()    # End timer
        duration = end_time - start_time
        print(f"⏱️ Function '{func.__name__}' took {duration:.4f} seconds")
        return result
    return wrapper



def get_company(auth_token, address_id):
    api_url = settings.CUSTOMER_API_URL + "customers/"
    headers = {
        'x-api-key': os.getenv('API_KEY'),
        'x-content-type': 'application/json',
        'x-auth-token': auth_token,
    }
    payload = {"address_id": address_id}
    try:
        response = requests.post(api_url, json=payload, headers=headers)
        if response.status_code == 200:
            data = response.json()
            return data.get('data', {}).get('CustomerNickName', None)
        else:
            return None
    except requests.RequestException as e:
        print(f"An error occurred: {e}")
        return None

def get_address_data(auth_token, address_id):
    api_url = settings.CUSTOMER_API_URL + "customers/"
    headers = {
        'x-api-key': os.getenv('API_KEY'),
        'x-content-type': 'application/json',
        'x-auth-token': auth_token,
    }
    payload = {"address_id": address_id}
    try:
        response = requests.post(api_url, json=payload, headers=headers)
        if response.status_code == 200:
            response_data = response.json()
            return response_data['data']
        else:
            return None
    except requests.RequestException as e:
        print(f"An error occurred: {e}")
        return None


def get_loadpoint(auth_token, load_point_id):
    api_url = settings.DELIVERY_API_URL + "loadpoints/"
    headers = {
        'x-api-key': os.getenv('API_KEY'),
        'x-content-type': 'application/json',
        'x-auth-token': auth_token,
    }
    payload = {"loadpoint_id": load_point_id}
    try:
        response = requests.post(api_url, json=payload, headers=headers)
        if response.status_code == 200:
            data = response.json()
            return data.get('data', {}).get('loadpoint_details', {}).get('LoadPointName', None)
        else:
            return None
    except requests.RequestException as e:
        print(f"An error occurred: {e}")
        return None


def get_incoterm(auth_token, incoterm_id):
    api_url = settings.DELIVERY_API_URL + "incoterms/"
    headers = {
        'x-api-key': os.getenv('API_KEY'),
        'x-content-type': 'application/json',
        'x-auth-token': auth_token,
    }
    payload = {"id": incoterm_id}
    try:
        response = requests.post(api_url, json=payload, headers=headers)
        if response.status_code == 200:
            data = response.json()
            return data.get('data', {}).get('Code', None)
        else:
            return None
    except requests.RequestException as e:
        print(f"An error occurred: {e}")
        return None


def get_productname(auth_token, product_id):
    api_url = settings.PRODUCT_API_URL + "products/"
    headers = {
        'x-api-key': os.getenv('API_KEY'),
        'x-content-type': 'application/json',
        'x-auth-token': auth_token,
    }
    payload = {"product_id": product_id}
    try:
        response = requests.post(api_url, json=payload, headers=headers)

        if response.status_code == 200:
            data = response.json()
            return data.get('data', {}).get('NickName', None)
        else:
            return None
    except requests.RequestException as e:
        # Handle exceptions, such as connection errors
        return None


def get_address(auth_token, address_id):
    api_url = settings.CUSTOMER_API_URL + "customers/"
    headers = {
        'x-api-key': os.getenv('API_KEY'),
        'x-content-type': 'application/json',
        'x-auth-token': auth_token,
    }
    payload = {"address_id": address_id}  # Assuming OrderedBy is the address identifier
    try:
        # Sending POST request to the external API
        response = requests.post(api_url, json=payload, headers=headers)

        # If the response is successful (status code 200)
        if response.status_code == 200:
            data = response.json()

            # Extract the address fields from the response
            address_data = data.get('data', {})
            address_line1 = address_data.get('AddressLine1', '')
            address_line2 = address_data.get('AddressLine2', '')
            city = address_data.get('City', '')
            state = address_data.get('State', '')
            country = address_data.get('Country', '')
            postal_code = address_data.get('PostalCode', '')
            full_address = ', '.join([
                str(field) for field in [
                    address_line1, address_line2, city, state, country, postal_code
                ] if field  # Only include non-empty fields
            ])

            # Remove any unnecessary commas (in case some fields are empty)
            return full_address.strip(', ')

        # If response status code is not 200, return None
        else:
            return None
    except requests.RequestException as e:
        # Handle any exception that occurs during the API request
        print(f"An error occurred: {e}")
        return None


def generate_quotation_filename(quotation_id, extension):
    # Assuming extension already includes the leading dot (e.g., '.pdf', '.jpg')
    unique_filename = f"Q{quotation_id}_{uuid.uuid4().hex}{extension}"
    return unique_filename

from django.db import transaction

class GetPriceMasterView(APIView):
    """Function to get price master details"""
    def get(self, request, *args, **kwargs):
        # function to get price master details
        price_master = PriceMaster.objects.filter()

        serializer_data = customer_serializer.BasePriceMasterSerializer(price_master, many=True).data

        return Response(
            {
                "status": "error",
                "code": 400,
                "data": serializer_data,
                "message": f"data fetched successfully",
            },
            status=status.HTTP_400_BAD_REQUEST,
        )


class CreateOrUpdateOrderRequestView(APIView):  # purchase order request creation/updation api

    def post(self, request, *args, **kwargs):
        # Extract data from the request body
        order_id = request.data.get('order_id')  # If present, this indicates an update
        exact_order_no = request.data.get('exact_order_no') if isinstance(request.data.get('exact_order_no'), str) else ""
        po_number = request.data.get('po_number') if isinstance(request.data.get('po_number'), str) else ""
        delivery_date = request.data.get('delivery_date', None)
        loading_date = request.data.get('loading_date', None)
        created_by = request.data.get('created_by')

        copy_order_id = request.data.get('copy_order_id', None)

        if copy_order_id:
            try:
                order_copy = Orders.objects.get(OrderNo=copy_order_id,IsDeleted=False)
                order_request_copy = OrderRequests.objects.get(Id=copy_order_id, IsDeleted=False)

                ordered_by = order_copy.OrderedCustomerId
                bill_to = order_copy.BillToCustomerId
                deliver_to = order_copy.DeliveryCustomerId
                filling_date = None
                # Purchase Order Number
                
                no_of_packings = order_copy.no_of_packings
                kg_per_packaging = order_copy.kg_per_packaging

                load_point_id = order_request_copy.LoadPointId
                incoterms_id = order_request_copy.IncoTermsId
                load_reference = order_copy.LoadReference

                delivery_time = request.data.get('delivery_time')
                delivery_time_interval = None
                product_id = order_copy.ProductId  # Product ID
                quantity = order_copy.Quantity
                quotation_files=[]
                ParentOrderId = copy_order_id
                order_copy = purchase_utils.get_order_price_link_id(copy_order_id)
                row_id = order_copy.PriceRowId if order_copy else None
                existing_applied_price = purchase_utils.get_applied_price(order_copy) if order_copy else None
                
                applied_price = existing_applied_price if existing_applied_price else None

            except Exception as e:
                raise ValidationError({
                "status_code": 400,
                "status": "error",
                "message": f"order not found str{e}",
                "data": ""
            }) 
        else:

            ordered_by = request.data.get('ordered_by') if isinstance(request.data.get('ordered_by'), int) else None
            bill_to = request.data.get('bill_to') if isinstance(request.data.get('bill_to'), int) else None
            deliver_to = request.data.get('deliver_to') if isinstance(request.data.get('deliver_to'), int) else None
            filling_date = request.data.get('filling_date', None )
            # Purchase Order Number
            
            no_of_packings = request.data.get('no_of_packings') if isinstance(request.data.get('no_of_packings'), int) else None
            kg_per_packaging = request.data.get('kg_per_packaging') if isinstance(request.data.get('kg_per_packaging'), int) else None

            load_point_id = request.data.get('load_point_id') if isinstance(request.data.get('load_point_id'),
                                                                            int) else None
            incoterms_id = request.data.get('incoterms_id') if isinstance(request.data.get('incoterms_id'), int) else None
            load_reference = request.data.get('load_reference') if isinstance(request.data.get('load_reference'),
                                                                            str) else ""  # Load Reference
            created_by = request.data.get('created_by')  # User ID of creator (used for updates too)
            delivery_time = request.data.get('delivery_time')
            delivery_time_interval = request.data.get('delivery_time_interval')
            product_id = request.data.get('product_id')  # Product ID
            quantity = request.data.get('quantity') if isinstance(request.data.get('quantity'), (int, float)) else None
            quotation_files = request.data.get('quotation_files', [])  # List of quotation files
            ParentOrderId = None
            row_id = request.data.get('row_id')
            applied_price = request.data.get('applied_price', None)

        if ordered_by is None or ordered_by == '' or product_id is None or product_id == '':
            return Response({
                "status_code": 400,
                "status": "error",
                "message": "Ordered by and product id are required"
            }, status=status.HTTP_400_BAD_REQUEST)

        address_data = fetch_data.get_address_data(ordered_by)
        product_data = fetch_data.get_product_data(product_id)
        need_origin_statement = False
        try:
            requirement = fetch_data.get_odoo_customer_requirement_data(address_data['exact_erp_address_id'], product_data['article_code'])
            # need_origin_statement = requirement.get('data')['is_outside_european_union'] if requirement.get('data') else False
            if address_data.get('has_origin_statement') and address_data.get('has_origin_statement') == 1:
                need_origin_statement = True
        except Exception as e:
            return Response(
                {
                    'status_code': status.HTTP_400_BAD_REQUEST,
                    'status': "error",
                    'message': f"Requirements data not found: {str(e)}",
                    'data': None,
                },
                status=status.HTTP_400_BAD_REQUEST)
        
        # if delivery_date is None or delivery_date == '' and loading_date is None or loading_date == ''
        #     return Response({
        #         "status_code": 400,
        #         "status": "error",
        #         "message": "Delivery date or loading date is required"
        #     }, status=status.HTTP_400_BAD_REQUEST)
        try:
            # If order_id is provided, it's an update request
            if order_id:
                if request.data.get('updated_by') is None or request.data.get('updated_by') == '':
                    return Response({
                        "status_code": 400,
                        "status": "error",
                        "message": "Updated by is required"
                    }, status=status.HTTP_400_BAD_REQUEST)
                if exact_order_no:
                    existing_order = OrderRequests.objects.exclude(Id=order_id).filter(ExactOrderNo=exact_order_no,
                                                                    IsDeleted=False).exists()
                    if existing_order:
                        return Response(
                            {
                                "status": "error",
                                "code": 400,
                                "message": f"Another order with Order No '{exact_order_no}' already exists. Please delete it and try again.",
                            },
                            status=status.HTTP_400_BAD_REQUEST,
                        )
                # Get the existing order request
                order_request = OrderRequests.objects.get(Id=order_id,IsDeleted=False)
                # if exact_order_no:
                order_request.ExactOrderNo = exact_order_no

                # if ordered_by:
                order_request.OrderedBy = ordered_by
                if ordered_by is not None:
                    order_request.OrderedCompany = get_company(request.headers.get('x-auth-token'), ordered_by)
                    order_request.OrderedAddress = get_address(request.headers.get('x-auth-token'), ordered_by)

                    address_data = get_address_data(request.headers.get('x-auth-token'), ordered_by)
                    OrderedCompany = address_data['CustomerNickName'] if 'CustomerNickName' in address_data.keys() else None
                    # OrderedCompany = get_company(request.headers.get('x-auth-token'), ordered_by)
                    OrderedAddress = get_address(request.headers.get('x-auth-token'), ordered_by)

                else:
                    order_request.OrderedCompany = ''
                    order_request.OrderedAddress = ''
                    need_origin_statement=False

                if need_origin_statement:
                    information = 'The exporter of the products covered by this document (Exporter Reference No BEREXBE0461104445) declares that, except where otherwise clearly indicated, these products are of EU preferential origin. \nGhent, '
                else:
                    information = None
                order_request.Information = information

                # if bill_to:
                order_request.BillTo = bill_to
                if bill_to is not None:
                    order_request.BillToCustomer = get_company(request.headers.get('x-auth-token'),
                                                                bill_to)
                    order_request.BillToAddress = get_address(request.headers.get('x-auth-token'), bill_to)
                else:
                    order_request.BillToCustomer = ''
                    order_request.BillToAddress = ''
                # if deliver_to:
                order_request.DeliverTo = deliver_to
                if deliver_to is not None:
                    order_request.DeliveryCustomer = get_company(request.headers.get('x-auth-token'),
                                                                    deliver_to)
                    order_request.DeliveryAddress = get_address(request.headers.get('x-auth-token'), deliver_to)
                else:
                    order_request.DeliveryCustomer = ''
                    order_request.DeliveryAddress = ''
                # if po_number:
                order_request.PurchaseOrderNo = po_number

                # if load_point_id:
                order_request.LoadPointId = load_point_id
                if load_point_id is not None:
                    order_request.LoadPoint = get_loadpoint(request.headers.get('x-auth-token'),
                                                            load_point_id)
                else:
                    order_request.LoadPoint = ''
                # if incoterms_id:
                order_request.IncoTermsId = incoterms_id
                if incoterms_id is not None:
                    order_request.IncoTerm = get_incoterm(request.headers.get('x-auth-token'),
                                                            incoterms_id)
                else:
                    order_request.IncoTerm = ''

                # if load_reference:
                order_request.LoadReference = load_reference

                # if created_by:
                order_request.CreatedBy = created_by
                # if delivery_date:
                order_request.DeliveryDate = delivery_date
                # if delivery_time:
                order_request.DeliveryTime = delivery_time
                # if delivery_time_interval:
                order_request.DeliveryTimeInterval = delivery_time_interval
                # if product_id:
                order_request.ProductId = product_id
                if product_id is not None:
                    order_request.Product = get_productname(request.headers.get('x-auth-token'),
                                                            product_id)
                else:
                    order_request.Product = ''
                # if quantity:
                order_request.Quantity = quantity
                if loading_date:
                    order_request.LoadingDate = loading_date

                order_request.FillingDate = filling_date

                order_request.kg_per_packaging=kg_per_packaging
                order_request.no_of_packings=no_of_packings

                # Save the updated order request
                order_request.save()

                # Log the update in OrderHistory
                OrderHistory.objects.create(
                    OrderRequestId=order_request.Id,
                    Updation="Order Request Updated",
                    UpdatedBy=request.data.get('updated_by'),
                    UpdatedOn=datetime.now(),  # Timestamp of creation
                    IsDeleted=False
                )
                
                if row_id is not None:
                    if row_id != '':
                        existing_entry = OrderPriceLink.objects.filter(OrderId=order_id, IsDeleted=0).first()
                        if existing_entry:
                            existing_entry.PriceRowId = row_id
                            existing_entry.save()
                        else:
                            # create price link
                            existing_entry = OrderPriceLink.objects.create(OrderId=order_id, PriceRowId=row_id)
                            new_price_data = {
                             
                            }
                            purchase_utils.create_or_update_linked_price(new_price_data, existing_entry)
                        if applied_price:
                            purchase_utils.create_or_update_linked_price(applied_price, existing_entry)
                    else:   
                        existing_entry = OrderPriceLink.objects.filter(OrderId=order_id, IsDeleted=0).first()
                        if existing_entry:
                            existing_entry.IsDeleted = 1
                            existing_entry.save()
            else:
                if created_by is None or created_by == '':
                    return Response({
                        "status_code": 400,
                        "status": "error",
                        "message": "Created by is required"
                    }, status=status.HTTP_400_BAD_REQUEST)
                if exact_order_no:
                    # Check if the ExactOrderNo already exists in the table for a create request
                    existing_order = OrderRequests.objects.filter(ExactOrderNo=exact_order_no, IsDeleted=False).exists()
                    if existing_order:
                        return Response(
                            {
                                "status": "error",
                                "code": 400,
                                "message":f"Another order with Order No '{exact_order_no}' already exists. Please delete it and try again."
                            },
                            status=status.HTTP_400_BAD_REQUEST,
                        )

                if ordered_by is not None:
                    address_data = get_address_data(request.headers.get('x-auth-token'), ordered_by)
                    OrderedCompany = address_data['CustomerNickName'] if 'CustomerNickName' in address_data.keys() else None
                    # OrderedCompany = get_company(request.headers.get('x-auth-token'), ordered_by)
                    OrderedAddress = get_address(request.headers.get('x-auth-token'), ordered_by)

                else:
                    OrderedCompany = ''
                    OrderedAddress = ''

                if need_origin_statement:
                    information = 'The exporter of the products covered by this document (Exporter Reference No BEREXBE0461104445) declares that, except where otherwise clearly indicated, these products are of EU preferential origin. \nGhent, '
                else:
                    information = None
                if bill_to is not None:
                    BillToCustomer = get_company(request.headers.get('x-auth-token'),bill_to)
                    BillToAddress = get_address(request.headers.get('x-auth-token'), bill_to)
                else:
                    BillToCustomer = ''
                    BillToAddress = ''
                if deliver_to is not None:
                    DeliveryCustomer = get_company(request.headers.get('x-auth-token'), deliver_to)
                    DeliveryAddress = get_address(request.headers.get('x-auth-token'), deliver_to)
                else:
                    DeliveryCustomer = ''
                    DeliveryAddress = ''
                if load_point_id is not None:
                    LoadPoint = get_loadpoint(request.headers.get('x-auth-token'), load_point_id)
                else:
                    LoadPoint = ''
                if incoterms_id is not None:
                    IncoTerm = get_incoterm(request.headers.get('x-auth-token'),
                                            incoterms_id)
                else:
                    IncoTerm = ''
                if product_id is not None:
                    Product = get_productname(request.headers.get('x-auth-token'), product_id)
                else:
                    Product = ''
                # Step 1: Create a new OrderRequest instance
                order_request = OrderRequests.objects.create(
                    ExactOrderNo=exact_order_no,
                    OrderedBy=ordered_by,
                    BillTo=bill_to,
                    DeliverTo=deliver_to,
                    PurchaseOrderNo=po_number,
                    LoadPointId=load_point_id,
                    IncoTermsId=incoterms_id,
                    LoadReference=load_reference,
                    CreatedBy=created_by,
                    DeliveryDate=delivery_date,
                    FillingDate=filling_date, 
                    kg_per_packaging=kg_per_packaging,
                    no_of_packings=no_of_packings,
                    DeliveryTime=delivery_time,
                    DeliveryTimeInterval=delivery_time_interval,
                    ProductId=product_id,
                    Quantity=quantity,
                    OrderedCompany=OrderedCompany,
                    OrderedAddress=OrderedAddress,
                    BillToCustomer=BillToCustomer,
                    BillToAddress=BillToAddress,
                    DeliveryCustomer=DeliveryCustomer,
                    DeliveryAddress=DeliveryAddress,
                    LoadPoint=LoadPoint,
                    IncoTerm=IncoTerm,
                    Product=Product,
                    LoadingDate=request.data.get('loading_date') if request.data.get('loading_date') else None,
                    Information=information,
                    ParentOrderId=ParentOrderId
                )

                # purchase_utils.create_packaging_info(
                #     order_request, kg_per_packaging, no_of_packings, product_id)

                # Log the creation in OrderHistory
                OrderHistory.objects.create(
                    OrderRequestId=order_request.Id,
                    Updation="Order Request Created",
                    UpdatedBy=created_by,
                    UpdatedOn=datetime.now(),  # Timestamp of creation 
                    IsDeleted=False
                )

                purchase_utils.copy_extra_charges(copy_order_id, order_request.Id)
                
                if row_id:
                    price_link = OrderPriceLink.objects.create(OrderId=order_request.Id, PriceRowId=row_id)
                    if applied_price:
                        purchase_utils.create_or_update_linked_price(applied_price, price_link)
            # Step 2: Save Quotation Files to a specific location and insert records
            saved_files = []
            for file_data in quotation_files:
                try:
                    # Extract the base64 content
                    file_content_base64 = file_data.get('file_data')

                    if not file_content_base64:
                        raise ValueError("No file data found in the request.")

                    # Check if the base64 string contains a MIME type (e.g., "data:image/png;base64,...")
                    if file_content_base64.startswith('data:'):
                        # Extract MIME type and actual file data
                        mime_type, file_content_base64 = file_content_base64.split(';base64,')
                    else:
                        mime_type = None
                    # Decode the base64 content
                    file_content = base64.b64decode(file_content_base64)

                    # Determine the file extension based on MIME type
                    if mime_type:
                        extension = MIME_TO_EXTENSION.get(mime_type, mimetypes.guess_extension(mime_type))
                        if not extension:
                            raise ValueError(f"Unsupported file type: {mime_type}")
                    else:
                        # Default to '.bin' if no MIME type is found
                        extension = '.bin'

                    # Generate a unique file name with the correct extension
                    unique_file_name = generate_quotation_filename(order_request.Id, extension)

                    # Create the directory if it doesn't exist
                    file_path = os.path.join(settings.MEDIA_ROOT, 'quotation_files', unique_file_name)
                    os.makedirs(os.path.dirname(file_path), exist_ok=True)
                    # Save the file
                    with open(file_path, 'wb') as destination:
                        destination.write(file_content)

                    # Insert a record into OrderRequestQuotation table
                    OrderRequestFiles.objects.create(
                        OrderId=order_request.Id,
                        FileName=unique_file_name
                    )
                    saved_files.append(unique_file_name)
                except Exception as e:
                    return Response(
                        {
                            "status": "error",
                            "code": 400,
                            "message": f"Error saving file: {str(e)}",
                        },
                        status=status.HTTP_400_BAD_REQUEST,
                    )
                
            return Response(
                {
                    "status": "success",
                    "code": 201 if not order_id else 200,
                    "message": "Order Request created successfully" if not order_id else "Order Request updated successfully",
                    "data": {'Id':order_request.Id},
                    "saved_files": saved_files,
                },
                status=status.HTTP_201_CREATED if not order_id else status.HTTP_200_OK,
            )
        except Exception as e:
            return Response( 
                {
                    "status": "error",
                    "code": 400,
                    "message": f"Error processing request: {str(e)}",
                },
                status=status.HTTP_400_BAD_REQUEST,
            )


class OrderRequestListView(APIView):
    def post(self, request, *args, **kwargs):
        page_size = int(request.data.get('page_size', 20))  # Default page size = 10
        today = datetime.now().date()
        five_days_later = today + timedelta(days=7)

        # Base filter condition (Only active, non-ordered records)
        filter_conditions = Q(IsDeleted=False, IsOrder=False)

        # Search Query Handling
        search_query = request.data.get('search_query', None)
        if search_query:
            product_ids = get_product_id_by_name(request.headers.get('x-auth-token'), search_query)
            product_condition = Q(ProductId__in=product_ids) if product_ids else Q()

            address_ids = get_address_ids_by_query(request.headers.get('x-auth-token'), search_query)
            address_condition = Q(
                Q(OrderedBy__in=address_ids) |
                Q(DeliverTo__in=address_ids) |
                Q(BillTo__in=address_ids)
            ) if address_ids else Q()

            filter_conditions &= Q(
                Q(ExactOrderNo__icontains=search_query) |
                Q(Quantity__icontains=search_query) |
                Q(PurchaseOrderNo__icontains=search_query) |
                Q(LoadReference__icontains=search_query) |
                Q(DeliveryDate__icontains=search_query) |
                product_condition |
                address_condition
            )
        # Apply filtering
        orders = (
            OrderRequests.objects.filter(filter_conditions)
            .annotate(
                effective_date=Coalesce('LoadingDate', 'DeliveryDate'),
                # Priority annotation
                priority=Case(
                    When(LoadingDate__gte=today, LoadingDate__lte=five_days_later, then=Value(1)),
                    # High priority by LoadingDate
                    When(LoadingDate__isnull=True, DeliveryDate__gte=today, DeliveryDate__lte=five_days_later,
                         then=Value(1)),  # High priority by DeliveryDate
                    When(DeliveryDate__lt=today, then=Value(2)),  # Low priority
                    default=Value(3),
                    output_field=IntegerField(),
                ),
                # Annotation to identify next 7 days orders
                is_immediate_delivery=Case(
                    When(LoadingDate__gte=today, LoadingDate__lte=five_days_later, then=Value(True)),
                    When(LoadingDate__isnull=True, DeliveryDate__gte=today, DeliveryDate__lte=five_days_later,
                         then=Value(True)),
                    default=Value(False),
                    output_field=BooleanField(),
                )
            )
        )

        sort_by = request.data.get('sort_column', None)
        sort_order = request.data.get('sort_order', 'desc')
        if sort_by:
            sort_field = f'-{sort_by}' if sort_order == 'desc' else sort_by
            sort_fields = ['priority', sort_field, '-CreatedAt']
        else:
            # Default to original logic if no sort_by
            sort_fields = ['priority', 'effective_date', '-CreatedAt']
        orders_next_7_days = orders.filter(
            Q(LoadingDate__gte=today, LoadingDate__lte=five_days_later) |
            Q(LoadingDate__isnull=True, DeliveryDate__gte=today, DeliveryDate__lte=five_days_later)
        ).order_by(*sort_fields)

        orders_other = orders.exclude(
            Id__in=orders_next_7_days.values_list('Id', flat=True)
        ).order_by(*sort_fields)
        # Merge both sorted lists
        orders = list(orders_next_7_days) + list(orders_other)

        # Pagination
        paginator = PageNumberPagination()
        paginator.page_size = page_size
        paginated_orders = paginator.paginate_queryset(orders, request)

        # Serialize the data
        serializer = RequestListSerializer(paginated_orders, many=True, context={'request': request})
        response_data = {
            "status": "success",
            "status_code": status.HTTP_200_OK,
            "message": "Orders fetched successfully",
            "count": len(orders),  # Total count
            "data": serializer.data
        }

        return Response(response_data, status=status.HTTP_200_OK)


class OrderRequestFilesView(APIView):
    def post(self, request):
        order_request_id = request.data.get('order_request_id')
        if order_request_id is None:
            return Response({
                "status_code": 400,
                "status": "error",
                "message": "Order request id is required"
            }, status=status.HTTP_400_BAD_REQUEST)

        files = OrderRequestFiles.objects.filter(OrderId=order_request_id, IsDeleted=False)
        serializer = OrderRequestFileSerializer(files, many=True)
        file_data = {}
        # file_data['BaseUrl'] = 'http://94.136.187.179:8005/po_service/serve-file/'
        file_data['BaseUrl'] = settings.ORDER_REQUEST_FILE_BASE_URL
        file_data['file_data'] = serializer.data
        return Response({
            "status_code": 200,
            "status": "success",
            "message": "Files fetched successfully",
            "data": file_data
        }, status=status.HTTP_200_OK)


def check_transporter_needed(auth_token, incoterm_id):
    if incoterm_id is not None and incoterm_id != '':
        api_url = settings.DELIVERY_API_URL + "incoterms/"
        headers = {
            'x-api-key': os.getenv('API_KEY'),
            'x-content-type': 'application/json',
            'x-auth-token': auth_token,
        }
        payload = {"id": incoterm_id}
        try:
            response = requests.post(api_url, json=payload, headers=headers)
            if response.status_code == 200:
                data = response.json()
                return data.get('data', {}).get('TransportNeeded', None)
            else:
                return None
        except requests.RequestException as e:
            print(f"An error occurred: {e}")
            return None
    else:
        return None


def get_product_articlecode(auth_token, product_id):
    api_url = settings.PRODUCT_API_URL + "products/"
    headers = {
        'x-api-key': os.getenv('API_KEY'),
        'x-content-type': 'application/json',
        'x-auth-token': auth_token,
    }
    payload = {"product_id": product_id}
    try:
        response = requests.post(api_url, json=payload, headers=headers)

        if response.status_code == 200:
            data = response.json()
            return data.get('data', {}).get('ArticleCode', None)
        else:
            return None
    except requests.RequestException as e:
        # Handle exceptions, such as connection errors
        return None


def get_address_code_from_id(auth_token,
                             address_id):  # fetch if any preferred time is there for customer's delivery address
    address_api = settings.CUSTOMER_API_URL + "customers/"
    headers = {
        'x-api-key': os.getenv('API_KEY'),
        'x-content-type': 'application/json',
        'x-auth-token': auth_token,
    }
    payload = {"address_id": address_id}
    try:
        response = requests.post(address_api, json=payload, headers=headers)
        if response.status_code == 200:
            address_data = response.json()
            if address_data["data"].get("ExactERPAddressId"):
                return address_data["data"].get("ExactERPAddressId")
            else:
                return ""
        else:
            print(f" address  API returned an error: {response.status_code} - {response.text}")
            return []
    except requests.RequestException as e:
        print(f"Error fetching address data: {e}")
        return []


def get_loading_slot_from_loadpoint(auth_token, load_point_id):
    api_url = settings.DELIVERY_API_URL + "loadpoints/"
    headers = {
        'x-api-key': os.getenv('API_KEY'),
        'x-content-type': 'application/json',
        'x-auth-token': auth_token,
    }
    payload = {"loadpoint_id": load_point_id}
    try:
        response = requests.post(api_url, json=payload, headers=headers)
        if response.status_code == 200:
            data = response.json()
            loading_slots = data.get('data', {}).get('loading_slots', [])
            if loading_slots and len(loading_slots) > 0:
                loading_slot_id = loading_slots[0].get('Id', None)
                loading_slot_name = loading_slots[0].get('Name', None)
            else:
                loading_slot_id = None
                loading_slot_name = None
            return {
                "loading_slot_id": loading_slot_id,
                "loading_slot_name": loading_slot_name
            }
        else:
            return None
    except requests.RequestException as e:
        print(f"An error occurred: {e}")
        return None

class OrderAttachmentFilesView(APIView):
    """Class to manage attachments of order request files"""
    def delete(self, request):
        """Function to delete Company """
        file_ids = request.data.get('file_ids', None)

        if file_ids:
            files = OrderRequestFiles.objects.filter(Id__in=file_ids, IsDeleted=False)
            files.update(IsDeleted=True)
    
        return Response(
                {"message": f"file with Ids {file_ids} deleted successfully"},
                status=200
            )


class OrderProcessInitiateView(APIView):
    def post(self, request, *args, **kwargs):
        order_id = request.data.get('order_request_id')
        if order_id and request.data.get('initiated_by'):
            # Fetch the order details based on order_id

            special_incoterms = ['FCA', 'EXW']

            order = OrderRequests.objects.filter(Id=order_id, IsDeleted=False).first()
            if order:
                # Serialize the order data
                serializer = OrderRequestSerializer(order, context={'request': request})
                order_data = serializer.data

                # transporter selection starts
                is_transporter_needed = check_transporter_needed(request.headers.get('x-auth-token'),
                                                                 order_data['IncoTermsId'])
                # Default null values for transporter fields
                order_data['TransporterId'] = ""
                order_data['TransporterName'] = ""
                order_data['TransportPrice'] = ""
                order_data['TransporterString'] = ""
                if is_transporter_needed:
                    if order.ParentOrderId:
                        # if order is copied, transort price will be taken form parent order
                        transporter_id, transporter_name, transporter_price = purchase_utils.get_transporter_and_price(
                            order.ParentOrderId)
                        order_data['TransporterId'] = transporter_id
                        order_data['TransporterName'] = transporter_name
                        order_data['TransportPrice'] = transporter_price
                        order_data['TransporterString'] = f"{transporter_name} (€ {convert_to_belgium_format(transporter_price)})" if transporter_name!="" else ""
                    else:
                        transporters = get_available_transporters(
                        request.headers.get('x-auth-token'), serializer.data['ProductId'],
                        serializer.data['LoadPointId'], serializer.data['DeliverTo'], 'Bulk',
                        serializer.data['IncoTermsId'])

                        if transporters:
                            # Check if transporters data exists and get the first row
                            transporter_name = transporters[0].get('Transporter')
                            transporter_price = float(transporters[0].get('TransportPrice'))
                            order_data['TransporterId'] = transporters[0].get('TransporterId')

                            order_data['TransporterName'] = transporter_name
                            # order_data['TransportPrice'] = convert_to_belgium_format(transporters[0].get('TransportPrice'))
                            order_data['TransportPrice'] = transporter_price
                            order_data['TransporterString'] = f"{transporter_name} (€ {convert_to_belgium_format(transporter_price)})" if transporter_name!="" else ""
                
                # transporter selection ends

                # loading date,time,delivery time calculation starts
                # delivery time starts
                # if is_transporter_needed: #need to plan only if we choose transporters(deciding based on inco term)
                # if order_data['DeliveryTime'] =='' and order_data['DeliveryTimeInterval'] =='':
                #     prfd_dtime = get_preferred_delivery_time(request.headers.get('x-auth-token'),order_data['DeliverTo'])
                #     if prfd_dtime['PreferredDTime'] is not None:
                #         order_data['DeliveryTime'] = prfd_dtime['PreferredDTime']
                #         #planned_dtime = generate_planned_dtime_from_time(prfd_dtime['PreferredDTime'])
                #     elif prfd_dtime['PreferredDTimeInterval'] is not None:
                #         order_data['DeliveryTimeInterval'] = prfd_dtime['PreferredDTimeInterval']
                #         #planned_dtime = generate_planned_dtime_from_time_interval(prfd_dtime['PreferredDTimeInterval'])
                if not is_transporter_needed:
                    order_data['DeliveryTime'] = ''

                # delivery time ends

                # loading date,time starts
                if order_data['LoadingDate'] == '' or order_data['LoadingDate'] is None:
                    loading_datetime_data = get_loading_datetime(request.headers.get('x-auth-token'),
                                                                 order_data['LoadPointId'], order_data['DeliverTo'])
                    if loading_datetime_data:
                        if loading_datetime_data['DateOffset'] is not None:
                            delivery_date = datetime.strptime(order_data['DeliveryDate'], "%Y-%m-%d")
                            loading_date = delivery_date - timedelta(days=loading_datetime_data['DateOffset'])
                            if loading_date.date() < date.today():
                                order_data['LoadingDate'] = order_data['DeliveryDate']
                            else:
                                order_data['LoadingDate'] = loading_date.strftime("%Y-%m-%d")
                        else:
                            order_data['LoadingDate'] = order_data['DeliveryDate']
                    else:
                        order_data['LoadingDate'] = order_data['DeliveryDate']

                    # checking the planned loading date is a holiday,if yes then shift to previous non holiday date
                    order_data['LoadingDate'] = get_previous_non_holiday(order_data['LoadingDate'])

                if order_data['IncoTerm'] in special_incoterms or order_data['ProductArticleCode'] == '50000':
                    price_filter_date = order_data['LoadingDate']
                else:
                    price_filter_date = order_data['DeliveryDate'] if order_data['DeliveryDate'] else order_data['LoadingDate']

                if serializer.data['LoadPointId'] == 2:
                    order_data['LoadingTime'] = '7h30-11h30 / 12h-14h30'
                else:
                    order_data['LoadingTime'] = ''
                # loading date,time ends

                # loading slot calculation starts
                if serializer.data['LoadPointId'] == 1:  # logic is required only if the loadpoint is PVS
                    allowed_loading_slots = get_allowed_loading_slots_for_product(request.headers.get('x-auth-token'),
                                                                                  serializer.data['ProductId'],
                                                                                  serializer.data['LoadPointId'])
                    order_data['LoadingSlotId'] = ""
                    order_data['LoadingSlot'] = ""
                    if allowed_loading_slots:
                        if order_data['LoadingTime'] != '':
                            for slot in allowed_loading_slots:
                                # Check if the slot is already booked
                                is_booked = BookedSlots.objects.filter(
                                    Q(SlotId=slot['Id']) &
                                    Q(Date=order_data['LoadingDate']) &
                                    Q(Time=order_data['LoadingTime']) &
                                    Q(IsDeleted=False)  # Ensure the slot is not soft deleted
                                ).exists()
                                if not is_booked:
                                    # since p3 and p4 are nearby slots/loading locations in PVS only one slot can be used at a time
                                    if slot['Slot'] == 'P3':
                                        # check p4 is boooked in the same slot
                                        is_booked = BookedSlots.objects.filter(
                                            Q(SlotId=2) &
                                            Q(Date=order_data['LoadingDate']) &
                                            Q(Time=order_data['LoadingTime']) &
                                            Q(IsDeleted=False)
                                        ).exists()
                                    elif slot['Slot'] == 'P4':
                                        # check p3 is boooked in the same slot
                                        is_booked = BookedSlots.objects.filter(
                                            Q(SlotId=1) &
                                            Q(Date=order_data['LoadingDate']) &
                                            Q(Time=order_data['LoadingTime']) &
                                            Q(IsDeleted=False)
                                        ).exists()
                                if not is_booked:
                                    order_data['LoadingSlotId'] = slot['Id']
                                    order_data['LoadingSlot'] = slot['Slot']
                                    break
                        else:
                            order_data['LoadingSlotId'] = allowed_loading_slots[0]['Id']
                            order_data['LoadingSlot'] = allowed_loading_slots[0]['Slot']
                else:
                    loading_slot_details = get_loading_slot_from_loadpoint(request.headers.get('x-auth-token'),
                                                                           serializer.data['LoadPointId'])
                    if loading_slot_details is not None:
                        order_data['LoadingSlotId'] = loading_slot_details['loading_slot_id']
                        order_data['LoadingSlot'] = loading_slot_details['loading_slot_name']
                    else:
                        order_data['LoadingSlotId'] = ''
                        order_data['LoadingSlot'] = ''
                # loading slot calculation ends
                # loading date,time,delivery time calculation ends

                # if packaging is other than bulk loading time is fixed ' 8h00 - 14h00'
                if order_data['Packaging']!='Bulk':
                    order_data['LoadingTime'] = "8h00 - 14h00"
 
                # price calculation starts
                if order_data['LoadingDate'] != '':
                    product_article_code = get_product_articlecode(request.headers.get('x-auth-token'),
                                                                   order_data['ProductId'])
                    ordered_by_address_code = get_address_code_from_id(request.headers.get('x-auth-token'),
                                                                       order_data['OrderedBy'])

                    # if order_data['IncoTerm'] == 'FCA'://commented since even for same article code,incoterm ,and validity period rate is different for different customer
                    #     price_master = PriceMaster.objects.filter(
                    #         ArticleCode=product_article_code,
                    #         IncoTermID=order_data['IncoTermsId'],
                    #         Packaging='Bulk',
                    #         # OrderedAddressId=ordered_by_address_code,removed as per the information from sajith on 30-01-2025
                    #         IsDeleted=0,
                    #         # MinQuantity__lte=order_data['Quantity'],  # Less than or equal to Min Quantity
                    #     ).filter(
                    #         Q(ValidityStartDate__lte=order_data['LoadingDate']) & Q(ValidityEndDate__gte=order_data['LoadingDate'])  # Date range
                    #     ).first()
                    # else:

                    deliver_to_address_code = get_address_code_from_id(request.headers.get('x-auth-token'),
                                                                       order_data['DeliverTo'])
                    formatted_quantity = Decimal(str(order_data['Quantity'])).quantize(Decimal('0.00'))

                    price_link = OrderPriceLink.objects.filter(OrderId=order_id, IsDeleted=0).first()
                    

                    if price_link:
                        linked_row = price_link.linked_prices.first()
                        loading_date_val = order_data.get('LoadingDate')
                        if isinstance(loading_date_val, str) and loading_date_val:
                            loading_date_obj = datetime.strptime(loading_date_val, "%Y-%m-%d").date()
                        elif isinstance(loading_date_val, (date, datetime)):
                            loading_date_obj = loading_date_val
                        else:
                            loading_date_obj = order.LoadingDate
                        
                        if linked_row and loading_date_obj and loading_date_obj >= linked_row.validity_start_date and loading_date_obj <= linked_row.validity_end_date:
                        # if linked_row:
                            order_data['TotalPrice'] = float(linked_row.price) * float(order_data['Quantity'])
                            order_data['Quarter'] = linked_row.quarter_name
                            order_data['QtyMsg'] = ''
                            order_data['Price'] = linked_row.price
                        else:
                            try:
                                price, quarter, qty_msg = purchase_utils.get_product_price_from_odoo(
                                    order_data['IncoTermsId'], order_data['LoadingDate'],
                                    product_article_code, order_data['Quantity'], deliver_to_address_code)
                                order_data['Price'] = price
                                order_data['Quarter'] = quarter
                                order_data['QtyMsg'] = qty_msg
                                order_data['TotalPrice'] = float(price) * float(order_data['Quantity'])
                            except:
                                order_data['TotalPrice'] = 0
                                order_data['Price'] = 0
                                order_data['Quarter'] = ''
                                order_data['QtyMsg'] = 'No price found'
                        
                    else:
                        try:
                            price, quarter, qty_msg = purchase_utils.get_product_price_from_odoo(
                                order_data['IncoTermsId'], order_data['LoadingDate'],
                                product_article_code, order_data['Quantity'], deliver_to_address_code)
                            order_data['Price'] = price
                            order_data['Quarter'] = quarter
                            order_data['QtyMsg'] = qty_msg
                            order_data['TotalPrice'] = float(price) * float(order_data['Quantity'])
                        except:
                            order_data['TotalPrice'] = 0
                            order_data['Price'] = 0
                            order_data['Quarter'] = ''
                            order_data['QtyMsg'] = 'No price found'


                    order_data['ExtraCharges'] = []
                    order_data['TotalExtraCharge'] = 0
                    if order_data['DeliveryDate'] is not None and order_data['DeliveryDate'] != '' and order_data[
                        'LoadingDate'] is not None and order_data['LoadingDate'] != '':
                        date_obj1 = datetime.strptime(order_data['DeliveryDate'], '%Y-%m-%d')
                        day_index1 = date_obj1.weekday()
                        delivery_day = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'][
                            day_index1]
                        date_obj2 = datetime.strptime(order_data['LoadingDate'], '%Y-%m-%d')
                        day_index2 = date_obj2.weekday()
                        loading_day = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'][
                            day_index2]
                        if delivery_day == 'Saturday' and loading_day == 'Friday':
                            additional_charge = {"charge_name": "Saturday Extra Charge", "charge_amount": 575}
                            order_data['ExtraCharges'].append(additional_charge)
                            # order_data['TotalPrice'] += 575
                            order_data['TotalExtraCharge'] += 575
                        elif delivery_day == 'Saturday' and loading_day == 'Saturday':
                            additional_charge = {"charge_name": "Saturday Extra Charge", "charge_amount": 955}
                            order_data['ExtraCharges'].append(additional_charge)
                            # order_data['TotalPrice'] += 955
                            order_data['TotalExtraCharge'] += 955
                        elif delivery_day == 'Sunday' and loading_day == 'Friday':
                            additional_charge = {"charge_name": "Sunday Extra Charge", "charge_amount": 580}
                            order_data['ExtraCharges'].append(additional_charge)
                            # order_data['TotalPrice'] += 580
                            order_data['TotalExtraCharge'] += 580
                        elif delivery_day == 'Sunday' and loading_day == 'Saturday':
                            additional_charge = {"charge_name": "Sunday Extra Charge", "charge_amount": 955}
                            order_data['ExtraCharges'].append(additional_charge)
                            # order_data['TotalPrice'] += 955
                            order_data['TotalExtraCharge'] += 955
                        elif delivery_day == 'Sunday' and loading_day == 'Sunday':
                            additional_charge = {"charge_name": "Sunday Extra Charge", "charge_amount": 1070}
                            order_data['ExtraCharges'].append(additional_charge)
                            # order_data['TotalPrice'] += 1070
                            order_data['TotalExtraCharge'] += 1070
                    if order_data['TotalPrice'] != 0:
                        order_data['TotalPrice'] = convert_to_belgium_format(order_data['TotalPrice'])
                    # order_data['TotalExtraCharge'] = convert_to_belgium_format(order_data['TotalExtraCharge'])
                    order_data['ExtraCharges'] = []
                    # order_data['TotalPrice'] = 0
                    order_data['TotalExtraCharge'] = 0
                    # price calculation ends

                # payment term section starts
                if os.environ.get('DJANGO_ENV') == 'staging':
                    order_data['PaymentTerm'] = '30 DAYS END OF MONTH'
                else:
                    if order_data['ExactOrderedAddressId'] is not None:
                        with connections['secondary'].cursor() as cursor:
                            query = f"select oms30_2 from betcd t1 join cicmpy t2 on t1.betcond=t2.PaymentCondition where t2.debnr= {order_data['ExactOrderedAddressId']}"
                            cursor.execute(query)
                            payment_details = cursor.fetchone()
                            if payment_details is None:
                                order_data['PaymentTerm'] = ''
                            else:
                                order_data['PaymentTerm'] = payment_details[0]
                    else:
                        order_data['PaymentTerm'] = ''
                # payment term section ends

                if order_data['Packaging'].lower() != 'bulk':
                    packing_data = purchase_utils.get_package_info(order, order_data['ProductId'])
                    order_data['pack_tare_weight'] = packing_data['pack_tare_weight']
                    order_data['nos_per_pallet'] = packing_data['nos_per_pallet']
                    order_data['no_of_pallets'] = packing_data['no_of_pallets']
                    order_data['pallet_weight'] = packing_data['pallet_weight']
                    order_data['product'] = packing_data['product']
                    order_data['dimension'] = packing_data['dimension']
                    order_data['no_of_packings'] = packing_data['no_of_packings']
                    order_data['dimension'] = packing_data['dimension']

                order_data['NeedSample'] = ''
                order_data['SampleReason'] = ''
                    

                exist = OrderHistory.objects.filter(
                    OrderRequestId=order_id,
                    Updation="Order Creation Initiated",
                    IsDeleted=False
                ).exists()
                if not exist:
                    OrderHistory.objects.create(
                        OrderRequestId=order_id,
                        Updation="Order Creation Initiated",
                        UpdatedBy=request.data.get('initiated_by'),
                        UpdatedOn=datetime.now(),  # Timestamp of creation
                        IsDeleted=False
                    )
                response_data = {
                    "status": "success",
                    "status_code": status.HTTP_200_OK,
                    "message": "Order details fetched successfully",
                    "data": order_data
                }
                return Response(response_data, status=status.HTTP_200_OK)
            else:
                return Response({
                    "status_code": 404,
                    "status": "error",
                    "message": "Order not found"
                }, status=status.HTTP_404_NOT_FOUND)
        else:
            return Response({
                "status_code": 400,
                "status": "error",
                "message": "Order request id and initiated by are required"
            }, status=status.HTTP_400_BAD_REQUEST)


class CostCenterAPIView(APIView):
    def post(self, request, *args, **kwargs):
        cost_center_id = request.data.get('id')  # Fetch `id` from the request body
        if cost_center_id:
            # Fetch specific cost center by ID
            try:
                cost_center = CostCenter.objects.filter(Id=cost_center_id, IsDeleted=False).values('Id', 'Code',
                                                                                                   'Description')
                response_data = {
                    "status": "success",
                    "status_code": status.HTTP_200_OK,
                    "message": "Cost center details fetched successfully",
                    "data": cost_center
                }
                return Response(response_data, status=status.HTTP_200_OK)
            except CostCenter.DoesNotExist:
                return Response({
                    "status_code": 404,
                    "status": "error",
                    "message": "Cost Center not found"
                }, status=status.HTTP_404_NOT_FOUND)
        else:
            # Fetch all cost centers
            cost_centers = CostCenter.objects.filter(IsDeleted=False).values('Id', 'Code', 'Description')
            response_data = {
                "status": "success",
                "status_code": status.HTTP_200_OK,
                "message": "Cost Center details fetched successfully",
                "data": cost_centers
            }
            return Response(response_data, status=status.HTTP_200_OK)

def update_address_relation(auth_token,product_article_code,delivery_address_id,ordered_address_id,billed_address_id):
    api_url = settings.CUSTOMER_API_URL + "update_address_relation/"
    headers = {
        'x-api-key': os.getenv('API_KEY'),
        'x-content-type': 'application/json',
        'x-auth-token': auth_token,
    }
    payload = {"article_code": product_article_code,"ship_to":delivery_address_id,"ordered_by":ordered_address_id,"invoice_to":billed_address_id}
    try:
        response = requests.post(api_url, json=payload, headers=headers)

        if response.status_code == 200:
            data = response.json()
            return data.get('data', {}).get('ArticleCode', None)
        else:
            return None
    except requests.RequestException as e:
        # Handle exceptions, such as connection errors
        return None

class OrderCreateView(APIView):
    def post(self, request):
        data = request.data
        if data['status'] == 2:  # order is confirming so validate all data
            # List of required fields
            required_fields = [
                "status", "order_id", "exact_order_no", "ordered_by", "bill_to", "deliver_to",
                "load_point_id", "incoterms_id", "created_by", "loading_slot", "loading_slot_id", "loading_date",
                "product_id", "product_name", "quantity", "price", "total_price","transport_price","invoice_code"
            ]
            # Iterate through each field and check if it's null or empty
            for field in required_fields:
                value = data.get(field)

                # If any required field is missing or empty
                if value is None or (isinstance(value, str) and value.strip() == ''):
                    # Return error response and stop the process
                    return Response({
                        "status_code": 400,
                        "status": "error",
                        "message": f"The field '{field}' is required and cannot be null or empty."
                    }, status=status.HTTP_400_BAD_REQUEST)
            not_empty_fields = ["transporter_id", "delivery_time", "cost_center_id"]
            for field in not_empty_fields:
                value = data.get(field)
                # If any required field empty
                if value == '':
                    # Return error response and stop the process
                    return Response({
                        "status_code": 400,
                        "status": "error",
                        "message": f"The field '{field}' cannot be empty,pass null if no data is there."
                    }, status=status.HTTP_400_BAD_REQUEST)
        else:
            not_empty_fields = ["transporter_id", "delivery_time", "loading_date", "loading_slot_id", "incoterms_id",
                                "quantity", "delivery_date", "cost_center_id"]
            for field in not_empty_fields:
                value = data.get(field)
                # If any required field empty
                if value == '':
                    # Return error response and stop the process
                    return Response({
                        "status_code": 400,
                        "status": "error",
                        "message": f"The field '{field}' cannot be empty,pass null if no data is there."
                    }, status=status.HTTP_400_BAD_REQUEST)

        payload_log = po_models.PayloadLog.objects.create(
                order_id=data['order_id'],
                request_payload=data,
                status="pending", 
                payload_type="order_confirmed"
            )

        # loading date and time should be less than delivery date and time
        if data.get('loading_date') and data.get('delivery_date'):
            # Convert dates to datetime objects
            loading_date = datetime.strptime(data.get('loading_date'), "%Y-%m-%d")
            delivery_date = datetime.strptime(data.get('delivery_date'), "%Y-%m-%d")

            # Validation checks
            if delivery_date < loading_date:
                return Response({
                    "status_code": 400,
                    "status": "error",
                    "message": "Delivery date must be later than or equal to the loading date"
                }, status=status.HTTP_400_BAD_REQUEST)

        existing_order = OrderRequests.objects.exclude(Id=data['order_id']).filter(ExactOrderNo=data['exact_order_no'],IsDeleted=False).exists()
        if existing_order:
            return Response(
                {
                    "status": "error",
                    "code": 400,
                    "message": f"Another order with Order No '{data['exact_order_no']}' already exists. Please delete it and try again."
                },
                status=status.HTTP_400_BAD_REQUEST,
            )
        try:
            with transaction.atomic():
                # Step 1: Update OrderRequests
                order_request = OrderRequests.objects.filter(Id=data['order_id']).first()
                if not order_request:
                    return Response({
                        "status_code": 404,
                        "status": "error",
                        "message": "Order request not found"
                    }, status=status.HTTP_404_NOT_FOUND)

                order_request.ExactOrderNo = data.get('exact_order_no', order_request.ExactOrderNo)
                order_request.Information = data.get('information', order_request.Information)
                order_request.ContainerNo = data.get('container_no', order_request.ContainerNo)
                order_request.OrderedBy = data.get('ordered_by', order_request.OrderedBy)
                order_request.BillTo = data.get('bill_to', order_request.BillTo)
                order_request.DeliverTo = data.get('deliver_to', order_request.DeliverTo)
                order_request.PurchaseOrderNo = data.get('po_number', order_request.PurchaseOrderNo)
                order_request.LoadPointId = data.get('load_point_id', order_request.LoadPointId)
                order_request.IncoTermsId = data.get('incoterms_id', order_request.IncoTermsId)
                order_request.FillingDate = data.get('filling_date', order_request.FillingDate)
                order_request.DeliveryDate = data.get('delivery_date', order_request.DeliveryDate)
                order_request.DeliveryTime = data.get('delivery_time', order_request.DeliveryTime)
                order_request.LoadingDate = data.get('loading_date', order_request.LoadingDate)
                order_request.DeliveryTimeInterval = data.get('delivery_time_interval',
                                                                order_request.DeliveryTimeInterval)
                order_request.ProductId = data.get('product_id', order_request.ProductId)
                order_request.Quantity = data.get('quantity', order_request.Quantity)
                order_request.UpdatedBy = data.get('created_by', order_request.UpdatedBy)
                order_request.UpdatedAt = datetime.now()
                order_request.IsOrder = 1
                order_request.Product = data.get('product_name', order_request.Product)

                ordered_address_details = get_address_details_from_id(request.headers.get('x-auth-token'),
                                                                        request.data.get('ordered_by'))
                order_request.OrderedCompany = ordered_address_details.get('CustomerName', order_request.OrderedCompany)
                order_request.OrderedAddress = ordered_address_details.get('CustomerAddress',
                                                                            order_request.OrderedAddress)

                delivery_address_details = get_address_details_from_id(request.headers.get('x-auth-token'),
                                                                        request.data.get('deliver_to'))
                order_request.DeliveryCustomer = delivery_address_details.get('CustomerName',
                                                                                order_request.DeliveryCustomer)
                order_request.DeliveryAddress = delivery_address_details.get('CustomerAddress',
                                                                                order_request.DeliveryAddress)

                billed_address_details = get_address_details_from_id(request.headers.get('x-auth-token'),
                                                                        request.data.get('bill_to'))
                order_request.BillToCustomer = billed_address_details.get('CustomerName', order_request.BillToCustomer)
                order_request.BillToAddress = billed_address_details.get('CustomerAddress', order_request.BillToAddress)

                # A packed order travels by road or by sea, and the mode decides
                # which fields, documents and emails apply. Both are order level
                # and apply to a road order too, so they live on the order.
                order_request.transport_mode = data.get(
                    'transport_mode', order_request.transport_mode)
                order_request.transport_delivery_location = data.get(
                    'transport_delivery_location',
                    order_request.transport_delivery_location)

                order_request.no_of_packings = data.get('no_of_packings', order_request.no_of_packings)
                order_request.kg_per_packaging = data.get('kg_per_packaging', order_request.kg_per_packaging)
                pack_tare_weight = data.get('pack_tare_weight', None)
                no_of_pallet = data.get('no_of_pallets', None)
                pallet_weight = data.get('pallet_weight', None)

                packing = purchase_utils.create_packaging_info(
                    order_request, order_request.kg_per_packaging, order_request.no_of_packings, pack_tare_weight,
                        no_of_pallet,  pallet_weight)

                # The sea leg and the three container appointments. Writes only
                # for a sea order; anything else soft deletes the row.
                purchase_utils.save_container_details(order_request, data)

                if data.get('incoterms_id') is not None:
                    order_request.IncoTerm = get_incoterm(request.headers.get('x-auth-token'),
                                                            data.get('incoterms_id'))
                else:
                    order_request.IncoTerm = None
                if data.get('load_point_id') is not None:
                    order_request.LoadPoint = get_loadpoint(request.headers.get('x-auth-token'),
                                                            data.get('load_point_id'))
                else:
                    order_request.LoadPoint = None
                order_request.LoadReference = data.get('load_reference', order_request.LoadReference)
                order_request.save()


                # Step 2: check order already exists against the request :might be saved earlier
                order_data = Orders.objects.filter(OrderNo=data['order_id'],IsDeleted=False)

                product_id = data.get('product_id', order_request.ProductId)
                with connection.cursor() as cursor:
                    cursor.execute("""
                        SELECT Packaging from ProductMaster where Id=%s
                    """, [
                        product_id
                    ])
                    prodcut_data = cursor.fetchone()
                packaging = prodcut_data[0] if prodcut_data else None

                if order_data.exists():  # Update with new data
                    order_data = order_data.first()
                    order_data.OrderNo = data.get('order_id', order_data.OrderNo)
                    order_data.LoadingDate = data.get('loading_date', order_data.LoadingDate)
                    order_data.LoadingTime = data.get('loading_time', order_data.LoadingTime)
                    order_data.LoadingSlotId = data.get('loading_slot_id', order_data.LoadingSlotId)
                    order_data.LoadingSlot = data.get('loading_slot', order_data.LoadingSlot)
                    order_data.TransporterId = data.get('transporter_id', order_data.TransporterId)
                    order_data.CostCenterId = data.get('cost_center_id', order_data.CostCenterId)
                    order_data.Price = data.get('price', order_data.Price)
                    order_data.Quarter = data.get('quarter', order_data.Quarter)
                    order_data.TotalPrice = data.get('total_price', order_data.TotalPrice)
                    order_data.Remarks = data.get('remarks', order_data.Remarks)
                    order_data.no_of_packings = data.get('no_of_packings', order_data.no_of_packings)
                    order_data.kg_per_packaging = data.get('kg_per_packaging', order_data.kg_per_packaging)
                    order_data.FillingDate = data.get('filling_date', order_data.FillingDate)
                    order_data.Packaging = packaging

                    if order_data.StatusId == 1:
                        order_data.StatusId = data.get('status', order_data.StatusId)
                    order_data.UpdatedBy = data.get('created_by', order_data.UpdatedBy)
                    order_data.UpdatedAt = datetime.now()

                    order_data.ExactOrderNo = data.get('exact_order_no', order_data.ExactOrderNo)
                    order_data.ProductId = data.get('product_id', order_data.ProductId)
                    order_data.ProductName = data.get('product_name', order_data.ProductName)
                    order_data.DeliveryDate = data.get('delivery_date', order_data.DeliveryDate)

                    order_data.OrderedCustomerId = ordered_address_details.get('CustomerId',
                                                                                order_data.OrderedCustomerId)
                    order_data.OrderedCustomerName = ordered_address_details.get('CustomerName',
                                                                                    order_data.OrderedCustomerName)
                    order_data.OrderedAddress = ordered_address_details.get('CustomerAddress',
                                                                            order_data.OrderedAddress)

                    order_data.BillToCustomerId = billed_address_details.get('CustomerId', order_data.BillToCustomerId)
                    order_data.BillToCustomerName = billed_address_details.get('CustomerName',
                                                                                order_data.BillToCustomerName)
                    order_data.BillToAddress = billed_address_details.get('CustomerAddress', order_data.BillToAddress)

                    delivery_address_details = get_address_details_from_id(request.headers.get('x-auth-token'),
                                                                            request.data.get('deliver_to'))
                    order_data.DeliveryCustomerId = delivery_address_details.get('CustomerId',
                                                                                    order_data.DeliveryCustomerId)
                    order_data.DeliveryCustomerName = delivery_address_details.get('CustomerName',
                                                                                    order_data.DeliveryCustomerName)
                    order_data.DeliveryAddress = delivery_address_details.get('CustomerAddress',
                                                                                order_data.DeliveryAddress)

                    order_data.LoadReference = data.get('load_reference', order_data.LoadReference)
                    order_data.StationReference = data.get('station_reference', order_data.StationReference)
                    
                    order_data.Quantity = data.get('quantity', order_data.Quantity)
                    order_data.ExtraCostBorneBy =  data.get('extra_cost_borne_by', None)
                    order_data.CostCenterId =  data.get('cost_center_id', None)
                    order_data.CostCenter =  data.get('cost_center', None)

                    order_data.NeedSample =  data.get('need_sample', None)
                    order_data.SampleReason =  data.get('sample_reason', None)

                    order_data.CourierDate =  data.get('courier_delivery_date', None)
                    order_data.CourierTime =  data.get('courier_delivery_time', None)

                    order_data.CourierPickupDate =  data.get('courier_pickup_date', None)
                    order_data.CourierPickupTime =  data.get('courier_pickup_time', None)

                    order_data.SampleOrderRef =  data.get('sample_order_ref', None)
                    
                    if data.get('incoterms_id') is not None:
                        order_data.IncoTerm = get_incoterm(request.headers.get('x-auth-token'),
                                                            data.get('incoterms_id'))
                    else:
                        order_data.IncoTerm = None
                    if data.get('load_point_id') is not None:
                        order_data.LoadPoint = get_loadpoint(request.headers.get('x-auth-token'),
                                                                data.get('load_point_id'))
                    else:
                        order_data.LoadPoint = None

                    payment_term = request.data.get("payment_term")  # Returns None if key is missing
                    if payment_term is not None:
                        order_data.PaymentTerm = data.get('payment_term', order_data.PaymentTerm)
                    if "transport_price" in request.data:
                        order_data.TransportPrice = data.get('transport_price', order_data.TransportPrice)
                    if "invoice_code" in request.data:
                        order_data.InvoiceCode = data.get('invoice_code', order_data.InvoiceCode)

                    status_check_date = order_data.DeliveryDate if order_data.DeliveryDate else order_data.LoadingDate
                    if status_check_date:
                        today = date.today()
                        status_check_date = datetime.strptime(status_check_date, "%Y-%m-%d").date()
                        # if status is delievred and delivery date is after today,chamnge status to confirmend
                        if order_data.StatusId==4 and status_check_date >= today:
                            order_data.StatusId = 3

                    order_data.save()
                    # Finding next po request in queue ends

                    ExtraCostBorneBy = order_data.ExtraCostBorneBy
                    extra_cost_note = 'Kindly note that any additional costs arising from this change will not be borne by PVS.'

                    if data['status'] == 2:
                        BookedSlots.objects.filter(OrderId=order_request.Id).update(IsDeleted=True)
                        if data['loading_slot_id'] is not None:
                            BookedSlots.objects.create(
                                OrderId=data['order_id'],
                                SlotId=data['loading_slot_id'],
                                Date=data['loading_date'],
                                Time=data['loading_time'],
                                CreatedOn=datetime.now(),
                                UpdatedOn=datetime.now()
                            )
                        exist = OrderHistory.objects.filter(
                            OrderRequestId=order_request.Id,
                            Updation="Order Planned",
                            IsDeleted=False
                        ).exists()
                        if exist:
                            # Log the update in OrderHistory
                            OrderHistory.objects.create(
                                OrderRequestId=order_request.Id,
                                Updation="Order Details Updated",
                                UpdatedBy=data['created_by'],
                                UpdatedOn=datetime.now()
                            )
                        else:
                            # Log the update in OrderHistory
                            OrderHistory.objects.create(
                                OrderRequestId=order_request.Id,
                                Updation="Order Planned",
                                UpdatedBy=data['created_by'],
                                UpdatedOn=datetime.now()
                            )
                    else:
                        # Log the update in OrderHistory
                        OrderHistory.objects.create(
                            OrderRequestId=order_request.Id,
                            Updation="Order Details Updated",
                            UpdatedBy=data['created_by'],
                            UpdatedOn=datetime.now()
                        )
                else:  # Insert into Orders table
                    ordered_address_details = get_address_details_from_id(request.headers.get('x-auth-token'),
                                                                            request.data.get('ordered_by'))
                    billed_address_details = get_address_details_from_id(request.headers.get('x-auth-token'),
                                                                            request.data.get('bill_to'))
                    delivery_address_details = get_address_details_from_id(request.headers.get('x-auth-token'),
                                                                            request.data.get('deliver_to'))

                    if data.get('incoterms_id') is not None:
                        inco_term = get_incoterm(request.headers.get('x-auth-token'),
                                                    data.get('incoterms_id'))
                    else:
                        inco_term = None
                    if data.get('load_point_id') is not None:
                        loading_point = get_loadpoint(request.headers.get('x-auth-token'),
                                                        data.get('load_point_id'))
                    else:
                        loading_point = None
                    payment_term = request.data.get("payment_term")
                    if payment_term is None:
                        payment_term = ''
                    TransportPrice = data.get('transport_price') if 'transport_price' in data else None
                    InvoiceCode = data.get('invoice_code') if 'invoice_code' in data else None

                    no_of_packings = data.get('no_of_packings', None)
                    kg_per_packaging = data.get('kg_per_packaging', None)
                    filling_date = data['filling_date']

                    new_order = Orders.objects.create(
                        OrderNo=data['order_id'],
                        LoadingDate=data['loading_date'],
                        FillingDate=filling_date,
                        LoadingTime=data['loading_time'],
                        LoadingSlotId=data['loading_slot_id'],
                        LoadingSlot=data['loading_slot'],
                        TransporterId=data['transporter_id'],
                        CostCenterId=data['cost_center_id'],
                        CostCenter=data['cost_center'],
                        Price=data['price'],
                        Quarter=data['quarter'],
                        TotalPrice=data['total_price'],
                        Remarks=data['remarks'],
                        StatusId=data['status'],
                        CreatedBy=data['created_by'],
                        CreatedAt=datetime.now(),
                        UpdatedBy=data['created_by'],
                        UpdatedAt=datetime.now(),
                        ExactOrderNo=data['exact_order_no'],
                        ProductId=data['product_id'],
                        ProductName=data['product_name'],
                        Packaging=packaging,
                        DeliveryDate=data['delivery_date'],
                        DeliveryCustomerId=delivery_address_details['CustomerId'],
                        DeliveryCustomerName=delivery_address_details['CustomerName'],
                        DeliveryAddress=delivery_address_details['CustomerAddress'],
                        BillToCustomerId=billed_address_details['CustomerId'],
                        BillToCustomerName=billed_address_details['CustomerName'],
                        BillToAddress=billed_address_details['CustomerAddress'],
                        OrderedCustomerId=ordered_address_details['CustomerId'],
                        OrderedCustomerName=ordered_address_details['CustomerName'],
                        OrderedAddress=ordered_address_details['CustomerAddress'],
                        LoadReference=data['load_reference'],
                        StationReference=data.get('station_reference', None),
                        Quantity=data['quantity'],
                        IncoTerm=inco_term,
                        LoadPoint=loading_point,
                        PaymentTerm=payment_term,
                        TransportPrice=TransportPrice,
                        InvoiceCode=InvoiceCode,
                        no_of_packings=no_of_packings,
                        kg_per_packaging=kg_per_packaging,
                        NeedSample =  data.get('need_sample', None),
                        SampleReason =  data.get('sample_reason', None),
                        CourierDate =  data.get('courier_delivery_date', None),
                        CourierTime =  data.get('courier_delivery_time', None), 
                        CourierPickupDate =  data.get('courier_pickup_date', None),
                        CourierPickupTime =  data.get('courier_pickup_time', None), 
                        SampleOrderRef =  data.get('sample_order_ref', None)
                    )
                    if data['status'] == 2:
                        # Log the update in OrderHistory
                        OrderHistory.objects.create(
                            OrderRequestId=order_request.Id,
                            Updation="Order Planned",
                            UpdatedBy=data['created_by'],
                            UpdatedOn=datetime.now()
                        )
                        if data['loading_slot_id'] is not None:
                            BookedSlots.objects.create(
                                OrderId=data['order_id'],
                                SlotId=data['loading_slot_id'],
                                Date=data['loading_date'],
                                Time=data['loading_time'],
                                CreatedOn=datetime.now(),
                                UpdatedOn=datetime.now()
                            )
                    elif data['status'] == 1:
                        # Log the update in OrderHistory
                        OrderHistory.objects.create(
                            OrderRequestId=order_request.Id,
                            Updation="Order Saved Temporarily",
                            UpdatedBy=data['created_by'],
                            UpdatedOn=datetime.now()
                        )
                    ExtraCostBorneBy = new_order.ExtraCostBorneBy
                    extra_cost_note = 'Kindly note that any additional costs arising from this change will not be borne by PVS.'
                
                # # Step 3: Insert into OrderCharges table
                # extra_charges = data.get('extra_charges', [])
                # # Step 2: check extra charges already exists against the order remove that add new one
                # order_charges = OrderCharges.objects.filter(OrderNo=data['order_id'])
                # if order_charges.exists():  # Check if there are any matching rows
                #     for charge in order_charges:
                #         charge.IsDeleted = 1
                #         charge.save()
                # for charge in extra_charges:
                #     OrderCharges.objects.create(
                #         OrderNo=data['order_id'],
                #         ChargeName=charge['charge_name'],
                #         Rate=charge['charge_amount'],
                #     )

                # Finding next po request in queue starts
                # filter_conditions = Q(IsDeleted=False, IsOrder=False)
                # today = datetime.now().date()
                # five_days_later = today + timedelta(days=7)
                # # Fetch the orders using the filter conditions
                # orders = (
                #     OrderRequests.objects.filter(filter_conditions)
                #     .annotate(
                #         # Priority annotation
                #         priority=Case(
                #             When(DeliveryDate__gte=today, DeliveryDate__lte=five_days_later, then=Value(1)),
                #             # High priority
                #             When(DeliveryDate__lt=today, then=Value(2)),  # Low priority
                #             default=Value(3),  # Default case for safety
                #             output_field=IntegerField(),
                #         ),
                #         # Annotation to identify next 5 days orders
                #         is_immediate_delivery=Case(
                #             When(DeliveryDate__gte=today, DeliveryDate__lte=five_days_later, then=Value(True)),
                #             default=Value(False),
                #             output_field=BooleanField(),
                #         )
                #     )
                #     .order_by('priority', 'DeliveryDate', 'CreatedAt')  # Priority first, then delivery or creation date
                # )

                # # Retrieve the topmost order (the first order after filtering and sorting)
                # top_order = orders.first()

                filter_conditions = Q(IsDeleted=False, IsOrder=False)
                today = datetime.now().date()
                five_days_later = today + timedelta(days=7)

                # Fetch the orders using the filter conditions
                orders = (
                    OrderRequests.objects.filter(filter_conditions)
                    .annotate(
                        # Priority annotation
                        priority=Case(
                            When(DeliveryDate__gte=today, DeliveryDate__lte=five_days_later, then=Value(1)),
                            # High priority
                            When(DeliveryDate__lt=today, then=Value(2)),  # Low priority
                            default=Value(3),  # Default case
                            output_field=IntegerField(),
                        ),
                        # Annotation to identify next 7 days orders
                        is_immediate_delivery=Case(
                            When(DeliveryDate__gte=today, DeliveryDate__lte=five_days_later, then=Value(True)),
                            default=Value(False),
                            output_field=BooleanField(),
                        )
                    )
                )

                # Separate sorting for two groups
                orders_next_7_days = orders.filter(DeliveryDate__gte=today, DeliveryDate__lte=five_days_later).order_by(
                    'priority', 'DeliveryDate', '-CreatedAt')
                orders_other = orders.exclude(DeliveryDate__gte=today, DeliveryDate__lte=five_days_later).order_by(
                    'CreatedAt')

                # Merge the two sorted lists
                sorted_orders = list(orders_next_7_days) + list(orders_other)

                # Retrieve the topmost order (the first order after filtering and sorting)
                top_order = sorted_orders[0] if sorted_orders else None

                if top_order:
                    # Serialize the data for the topmost order
                    serializer = OrderRequestSerializer(top_order, context={'request': request})
                    top_request_details = serializer.data
                    top_order_id = top_order.Id
                else:
                    top_order_id = None
                    top_request_details = None

                #if order is confirmed save articlecode,ship to,billto and invoiceto relation in db
                if data['status'] == 2:
                    product_article_code = get_product_articlecode(request.headers.get('x-auth-token'), data['product_id'])
                    if product_article_code:
                        update_address_relation(request.headers.get('x-auth-token'),product_article_code,delivery_address_details.get('ExactERPAddressId'),ordered_address_details.get('ExactERPAddressId'),billed_address_details.get('ExactERPAddressId'))

                return Response({
                    "status_code": 200,
                    "status": "success",
                    "message": "Order created successfully",
                    "data": {
                        "next_po_request": top_order_id,
                        "details": top_request_details, 
                        "extra_cost_note": extra_cost_note,
                        "extra_cost_borne_by": ExtraCostBorneBy,
                    }
                }, status=status.HTTP_200_OK)
        except Exception as e:
            return Response({
                "status_code": 500,
                "status": "error",
                "message": "An error occurred", "error": str(e),
                "data": None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class OrderHistoryView(APIView):
    def post(self, request):
        try:
            # Validate request data (check if OrderRequestId is provided)
            order_request_id = request.data.get('order_id')
            if not order_request_id:
                return Response({
                    "status_code": 400,
                    "status": "error",
                    "message": "Order request id is required"
                }, status=status.HTTP_400_BAD_REQUEST)

            # Fetch the OrderHistory entries based on OrderRequestId
            order_history = OrderHistory.objects.filter(OrderRequestId=order_request_id, IsDeleted=False)

            if order_history.exists():
                serializer = OrderHistorySerializer(order_history, many=True, context={'request': request})
                response_data = {
                    "status_code": status.HTTP_200_OK,
                    "status": "success",
                    "message": "Order history fetched successfully.",
                    "data": serializer.data
                }
                return Response(response_data, status=status.HTTP_200_OK)
            else:
                response_data = {
                    "status_code": status.HTTP_404_NOT_FOUND,
                    "status": "error",
                    "message": "No history found for the given OrderRequestId.",
                    "data": []
                }
                return Response(response_data, status=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            response_data = {
                "status_code": status.HTTP_400_BAD_REQUEST,
                "status": "error",
                "message": f"An error occurred: {str(e)}",
                "data": []
            }
            return Response(response_data, status=status.HTTP_400_BAD_REQUEST)



# class SimilarOrderView(APIView):
#     def post(self, request, *args, **kwargs):
#         order_id = request.data.get('order_id')
#         if not order_id:
#             return Response({
#                 "status_code": 400,
#                 "status": "failed",
#                 "message": "Order Id is required",
#                 "error": "Order Id is missing in the request",
#                 "data": None
#             }, status=status.HTTP_400_BAD_REQUEST)
#
#         try:
#             # Fetch the order
#             order = OrderRequests.objects.get(Id=order_id, IsDeleted=False)
#
#             # Filter OrderRequests linked to Orders with StatusId in (2,3,4)
#             valid_order_ids = Orders.objects.filter(
#                 OrderNo=OuterRef('Id'),
#                 StatusId__in=[2, 3, 4],
#                 IsDeleted=False
#             ).values('OrderNo')
#
#             # Base filters
#             base_filters = {
#                 'OrderedBy': order.OrderedBy,
#                 'ProductId': order.ProductId,
#                 'LoadPointId': order.LoadPointId,
#                 'IsDeleted': False,
#                 'IsOrder': True,
#             }
#
#             # Apply Subquery annotation for filtering
#             filtered_queryset = OrderRequests.objects.annotate(
#                 has_valid_order=Subquery(valid_order_ids[:1])
#             ).filter(has_valid_order__isnull=False)
#
#             # Dynamically build Q objects with decreasing specificity
#             conditions = []
#
#             if all([order.DeliverTo, order.BillTo, order.Quantity, order.IncoTermsId]):
#                 conditions.append(Q(**{
#                     **base_filters,
#                     'DeliverTo': order.DeliverTo,
#                     'BillTo': order.BillTo,
#                     'Quantity': order.Quantity,
#                     'IncoTermsId': order.IncoTermsId
#                 }))
#
#             if all([order.DeliverTo, order.BillTo, order.Quantity]):
#                 conditions.append(Q(**{
#                     **base_filters,
#                     'DeliverTo': order.DeliverTo,
#                     'BillTo': order.BillTo,
#                     'Quantity': order.Quantity,
#                 }))
#
#             if all([order.DeliverTo, order.BillTo]):
#                 conditions.append(Q(**{
#                     **base_filters,
#                     'DeliverTo': order.DeliverTo,
#                     'BillTo': order.BillTo,
#                 }))
#
#             if order.DeliverTo:
#                 conditions.append(Q(**{
#                     **base_filters,
#                     'DeliverTo': order.DeliverTo,
#                 }))
#
#             # Most basic filter
#             conditions.append(Q(**base_filters))
#
#             # List to store all similar orders
#             similar_orders = []
#
#             for condition in conditions:
#                 matching_orders = filtered_queryset.exclude(Id=order.Id).filter(condition).values(
#                     'Id', 'ExactOrderNo', 'DeliveryDate'
#                 ).order_by('-Id')
#
#                 if matching_orders.exists():
#                     for o in matching_orders:
#                         similar_orders.append(o)
#
#             # Remove duplicates using dict
#             unique_orders = list({
#                 o['Id']: {
#                     'Id': o['Id'],
#                     'OrderNo': o['ExactOrderNo'],
#                     'DeliveryDate':o['DeliveryDate'].strftime('%d.%m.%Y')
#                 }
#                 for o in similar_orders
#             }.values())
#
#             # Determine if current order is confirmed
#             orders = Orders.objects.filter(OrderNo=order_id, IsDeleted=False).first()
#             is_order = 1 if orders and orders.StatusId != 1 else 0
#
#             response = {
#                 "unique_orders": unique_orders,
#                 "is_order": is_order
#             }
#
#             return Response({
#                 "status_code": 200,
#                 "status": "success",
#                 "message": "Order details fetched successfully.",
#                 "data": response,
#             }, status=status.HTTP_200_OK)
#
#         except OrderRequests.DoesNotExist:
#             return Response({
#                 "status_code": 404,
#                 "status": "failed",
#                 "message": "Order not found",
#                 "error": "The order with the provided ID does not exist",
#                 "data": None
#             }, status=status.HTTP_404_NOT_FOUND)
#
#         except Exception as e:
#             import traceback
#             traceback_str = traceback.format_exc()
#             return Response({
#                 "status_code": 500,
#                 "status": "failed",
#                 "message": "An error occurred",
#                 "error": str(e),
#                 "trace": traceback_str,
#                 "data": None
#             }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

class SearchOrdersAPIView(APIView):
    def post(self, request):
        try:
            # Extract search string from request data
            search_string = request.data.get('search_string', '')
            if not search_string:
                return Response(
                    {
                        'status_code': status.HTTP_400_BAD_REQUEST,
                        'status': 'error',
                        'message': "Search string is required.",
                        'data': None,
                    },
                    status=status.HTTP_400_BAD_REQUEST
                )

            # Check if the search string matches a valid date format
            try:
                search_date = datetime.strptime(search_string, '%d.%m.%Y').date()
            except ValueError:
                search_date = None

            # Query the database
            orders = OrderRequests.objects.filter(
                Q(ExactOrderNo__icontains=search_string) | Q(DeliveryDate=search_date),
                IsDelivered=True,
                IsDeleted=False
            ).values('Id', 'ExactOrderNo', 'DeliveryDate')

            # Format the response data
            response_data = [
                {
                    'Id': order['Id'],
                    'OrderNo': order['ExactOrderNo'],
                    'DeliveryDate': order['DeliveryDate'].strftime('%d.%m.%Y')  # Format DeliveryDate
                }
                for order in orders
            ]

            # Return response
            return Response(
                {
                    'status_code': status.HTTP_200_OK,
                    'status': 'success',
                    'message': f"{len(response_data)} order(s) found matching the search string.",
                    'data': response_data,
                },
                status=status.HTTP_200_OK
            )

        except Exception as e:
            return Response(
                {
                    'status_code': status.HTTP_400_BAD_REQUEST,
                    'status': 'error',
                    'message': f"An error occurred: {str(e)}",
                    'data': None,
                },
                status=status.HTTP_400_BAD_REQUEST
            )


class OrderDetailsAPIView(APIView):
    def post(self, request):
        try: 
            # Extract the order ID from the request body
            order_id = request.data.get('order_id')
            new_order_id = request.data.get('new_order_id')
            # Check if either order_id or new_order_id exists
            if order_id:
                orderid = order_id
            elif new_order_id:
                # Fetch the order
                order = OrderRequests.objects.get(Id=new_order_id, IsDeleted=False)
                conditions = [
                    Q(OrderedBy=order.OrderedBy, ProductId=order.ProductId, DeliverTo=order.DeliverTo,
                        BillTo=order.BillTo, Quantity=order.Quantity, IncoTermsId=order.IncoTermsId, IsDelivered=True,
                        IsDeleted=False, IsOrder=True),
                    Q(OrderedBy=order.OrderedBy, ProductId=order.ProductId, DeliverTo=order.DeliverTo,
                        BillTo=order.BillTo, Quantity=order.Quantity, IsDelivered=True, IsDeleted=False, IsOrder=True),
                    Q(OrderedBy=order.OrderedBy, ProductId=order.ProductId, DeliverTo=order.DeliverTo,
                        BillTo=order.BillTo, IsDelivered=True, IsDeleted=False, IsOrder=True),
                    Q(OrderedBy=order.OrderedBy, ProductId=order.ProductId, DeliverTo=order.DeliverTo, IsDelivered=True,
                        IsDeleted=False, IsOrder=True),
                    Q(OrderedBy=order.OrderedBy, ProductId=order.ProductId, IsDelivered=True, IsDeleted=False,
                        IsOrder=True),
                ]
                order_id = None
                for condition in conditions:
                    # Check if there are orders matching the condition (excluding the current order) and get the most recent one
                    top_order = OrderRequests.objects.exclude(Id=order.Id).filter(condition).order_by('-Id').first()
                    if top_order:
                        order_id = top_order.Id
                        break
                if order_id is None:
                    return Response(
                        {
                            'status_code': status.HTTP_200_OK,
                            'status': 'success',
                            'message': "No orders found",
                            'data': None,
                        },
                        status=status.HTTP_200_OK
                    )
            else:
                return Response(
                    {
                        'status_code': status.HTTP_400_BAD_REQUEST,
                        'status': 'error',
                        'message': "order_id or new_order_id is required.",
                        'data': None,
                    },
                    status=status.HTTP_400_BAD_REQUEST
                )
            # Fetch the order request details
            order_request = OrderRequests.objects.filter(Id=order_id, IsOrder=True,IsDeleted=False).first()
            if not order_request:
                return Response(
                    {
                        'status_code': status.HTTP_404_NOT_FOUND,
                        'status': 'error',
                        'message': f"No order found with Id: {order_id}",
                        'data': None,
                    },
                    status=status.HTTP_404_NOT_FOUND
                )
            serializer = OrderRequestSerializer(order_request, context={'request': request})
            order_request_details = serializer.data
            order_details = Orders.objects.filter(OrderNo=order_id, IsDeleted=False).first()
            serializer = OrderDetailsSerializer(order_details, context={'request': request})
            order_details = serializer.data
            order_details['TotalPrice'] = Decimal(order_request_details['Quantity']) * Decimal(order_details['Price'])
            if order_details['TransporterName'] != "":
                order_details['TransporterString'] = order_details['TransporterName'] + (f" (€ {convert_to_belgium_format(order_details['TransportPrice'])})" if order_details['TransportPrice'] is not None else "")
            else:
                order_details['TransporterString'] = None
            # Fetch the related order charges
            order_charges = list(
                OrderCharges.objects.filter(OrderNo=order_id).values(
                    'Id', 'ChargeName', 'Rate', 'ExtraChargeId'
                )
            )
            # Combine the data
            combined_data = {**order_request_details, **order_details}
            order_charges_set = OrderCharges.objects.filter(OrderNo=order_id, IsDeleted=False).annotate(
                    charge_name=F('ChargeName'),
                    charge_amount=F('Rate')
                ).values(
                    'Id', 'charge_name', 'charge_amount', 'ExtraChargeId'
                )

            # combined_data['ExtraCharges'] = list(
            #     OrderCharges.objects.filter(OrderNo=order_id, IsDeleted=False).annotate(
            #         charge_name=F('ChargeName'),
            #         charge_amount=F('Rate')
            #     ).values(
            #         'Id', 'charge_name', 'charge_amount', 'ExtraChargeId'
            #     )
            # )

            order_charges_set = OrderCharges.objects.filter(OrderNo=order_id, IsDeleted=False)
            order_charges = []
            for oc in order_charges_set:
                order_charges.append({
                    'Id': oc.Id,
                    "charge_name": oc.ChargeName,
                    "charge_amount": oc.Rate,
                    "ExtraChargeId": oc.ExtraChargeId,
                    "IsExxon": oc.get_is_exxon if oc.get_is_exxon else 0,
                    "ArticleCode": oc.get_charge_article_code if oc.get_charge_article_code else None,
                })

            # combined_data['ExtraCharges'] = order_charges
            total_sum = \
            OrderCharges.objects.filter(OrderNo=order_id, IsDeleted=False).aggregate(total_amount=Sum('Rate'))[
                'total_amount']
            total_extra_charge = total_sum if total_sum else 0
            combined_data['TotalExtraCharge'] = convert_to_belgium_format(total_extra_charge)

            if combined_data['Packaging'].lower() != 'bulk':
                packing_data = purchase_utils.get_package_info(order_request, combined_data['ProductId'])
                combined_data['pack_tare_weight'] = packing_data['pack_tare_weight']
                combined_data['nos_per_pallet'] = packing_data['nos_per_pallet']
                combined_data['no_of_pallets'] = packing_data['no_of_pallets']
                combined_data['pallet_weight'] = packing_data['pallet_weight']
                combined_data['product'] = packing_data['product']
                combined_data['dimension'] = packing_data['dimension']
                combined_data['no_of_packings'] = packing_data['no_of_packings']
                combined_data['dimension'] = packing_data['dimension']


            return Response(
                {
                    'status_code': status.HTTP_200_OK,
                    'status': 'success',
                    'message': "Order details retrieved successfully.",
                    'data': combined_data,
                },
                status=status.HTTP_200_OK
            )

        except Exception as e:
            return Response(
                {
                    'status_code': status.HTTP_500_INTERNAL_SERVER_ERROR,
                    'status': 'error',
                    'message': f"An error occurred: {str(e)}",
                    'data': None,
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )


class OrderListPagination(PageNumberPagination):
    """
    Pagination class for the Order List API view.
    """
    page_size = 10  # Default page size
    page_size_query_param = 'page_size'  # Allow dynamic page size
    max_page_size = 100  # Maximum page size


class OrderListAPIView(APIView): 
    def post(self, request):
        try:
            # Get pagination parameters from request body
            page_size = request.data.get('page_size', 20)  # Default to 10 if not provided
            page = request.data.get('page', 1)  # Default to page 1 if not provided

            # Pagination setup
            paginator = OrderListPagination()
            paginator.page_size = page_size
            paginator.page = page

            # Filter conditions setup
            filter_conditions = Q(IsDeleted=False)

            # Apply additional filters based on request parameters

            if request.data.get('status_id') is not None:
                filter_conditions &= Q(StatusId=request.data.get('status_id'))
            if request.data.get('product_id') is not None:
                filter_conditions &= Q(ProductId=request.data.get('product_id'))
            if request.data.get('created_date_from') and request.data.get('created_date_to'):
                new_created_date_to = datetime.strptime(request.data.get('created_date_to'), '%Y-%m-%d') + timedelta(
                    days=1)
                new_created_date_to_str = new_created_date_to.strftime('%Y-%m-%d')
                filter_conditions &= Q(
                    CreatedAt__range=[request.data.get('created_date_from'), new_created_date_to_str])
            if request.data.get('client_id') is not None:
                filter_conditions &= Q(OrderedCustomerId=request.data.get('client_id')) | Q(
                    BillToCustomerId=request.data.get('client_id')) | Q(
                    DeliveryCustomerId=request.data.get('client_id'))
            if request.data.get('delivery_date_from') and request.data.get('delivery_date_to'):
                filter_conditions &= Q(
                    DeliveryDate__range=[request.data.get('delivery_date_from'), request.data.get('delivery_date_to')])
            if request.data.get('loading_date_from') and request.data.get('loading_date_to'):
                filter_conditions &= Q(
                    LoadingDate__range=[request.data.get('loading_date_from'), request.data.get('loading_date_to')])
            if request.data.get('search_query') is not None:
                search_query = request.data.get('search_query')
                filter_conditions &= Q(
                    Q(ExactOrderNo__icontains=search_query) |
                    Q(OrderedCustomerName__icontains=search_query) |
                    Q(BillToCustomerName__icontains=search_query) |
                    Q(DeliveryCustomerName__icontains=search_query) |
                    Q(ProductName__icontains=search_query)
                )

            # Default sorting fields (if no sort_by is provided)
            default_sort_fields = ['-UpdatedAt']  # Default to descending order of UpdatedAt

            # Get sorting parameters from the request body
            sort_by = request.data.get('sort_column', None)  # Field by which to sort
            sort_order = request.data.get('sort_order', 'asc')  # 'asc' or 'desc'

            # Map sort_order to '-' for descending if 'desc' is passed
            if sort_order == 'desc' and sort_by:
                sort_by = '-' + sort_by
            elif sort_order == 'asc' and sort_by:
                sort_by = sort_by

            # Apply annotations and filter conditions, and apply dynamic sorting
            orders_queryset = Orders.objects.filter(filter_conditions)
            packaging = request.data.get('packaging')
            
            if packaging is not None  and packaging!='All':
                orders_queryset = orders_queryset.filter(Packaging=packaging)

            if sort_by:
                orders_queryset = orders_queryset.order_by(sort_by)
            else:
                # Apply default sorting if no sort_by is provided
                orders_queryset = orders_queryset.order_by(*default_sort_fields)

            # Paginate the queryset
            paginated_orders = paginator.paginate_queryset(orders_queryset, request)
            # Prepare the response data for each order
            order_data = []
            for order in paginated_orders:
                order_details = {}
                order_request_id = order.OrderNo

                try:
                    # Fetch related OrderRequest details using the OrderNo
                    order_request = OrderRequests.objects.filter(Id=order_request_id, IsOrder=True,IsDeleted=False).first()
                    if order_request:
                        order_request_serializer = OrderRequestListSerializer(
                            order_request, context={'request': request})
                        serialized_data = order_request_serializer.data 
                        # Add order request data to the order_details
                        order_details.update(serialized_data)

                except OrderRequests.DoesNotExist:
                    order_details['order_request'] = {}

                order_details_instance = Orders.objects.filter(OrderNo=order_request_id, IsDeleted=False) \
                    .values('StatusId', 'CreatedAt', 'LoadingDate').first()

                if order_details_instance and 'StatusId' in order_details_instance:
                    status_id = order_details_instance['StatusId']

                    # Fetch the related OrderStatus based on the StatusId
                    order_status = OrderStatus.objects.filter(OrderStatusId=status_id).values('Status').first()

                    if order_status:
                        # Add the necessary details to order_details
                        order_details['StatusId'] = status_id
                        order_details['OrderStatus'] = order_status['Status']
                        if status_id==5:
                            status_data = purchase_utils.get_status_data(order_request_id)

                            for key, value in status_data.items():
                                order_details[key] = value


                    order_details['FormattedCreatedAt'] = order_details_instance['CreatedAt'].strftime("%d.%m.%Y")
                if order_details_instance['LoadingDate']:
                    order_details['FormattedLoadingDate'] = order_details_instance['LoadingDate'].strftime("%d.%m.%Y")

                # Add the combined order details and charges to the response data
                order_data.append({
                    'order_details': order_details,  # Combined order details (order_request + order_details)
                })

            # Get paginated response
            paginated_response = paginator.get_paginated_response(order_data)

            # Prepare final response structure
            response_data = {
                'status_code': status.HTTP_200_OK,
                'status': 'success',
                'message': "Order list retrieved successfully.",
                'count': paginated_response.data['count'],
                'next': paginated_response.data['next'],
                'previous': paginated_response.data['previous'],
                'data': paginated_response.data['results']
            }

            # Return the response
            return Response(response_data, status=status.HTTP_200_OK)

        except Exception as e:
            return Response(
                {
                    'status_code': status.HTTP_500_INTERNAL_SERVER_ERROR,
                    'status': 'error',
                    'message': f"An error occurred: {str(e)}",
                    'data': None,
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )


class OrderStatusListView(APIView):
    def post(self, request, *args, **kwargs):
        order_statuses = OrderStatus.objects.filter(IsDeleted=False)
        serializer = OrderStatusSerializer(order_statuses, many=True)
        return Response(
            {
                'status_code': status.HTTP_200_OK,
                'status': 'success',
                'message': "Order status retrieved successfully.",
                'data': serializer.data,
            },
            status=status.HTTP_200_OK
        )


class UpdateOrderStatusView(APIView):
    """
    Update the status(confirmed or cancelled) of multiple orders
    """

    def post(self, request):
        # Deserialize the input data
        serializer = UpdateOrderStatusSerializer(data=request.data)

        if serializer.is_valid():
            order_status = serializer.validated_data['order_status']
            if request.data.get('all_checked') is not None:
                all_checked = request.data.get('all_checked')
                if all_checked == 1:
                    # Filter conditions setup
                    filter_conditions = Q(IsDeleted=False)

                    # Apply additional filters based on request parameters
                    if request.data.get('status_id') is not None:
                        filter_conditions &= Q(StatusId=request.data.get('status_id'))
                    if request.data.get('product_id') is not None:
                        filter_conditions &= Q(ProductId=request.data.get('product_id'))
                    if request.data.get('created_date_from') and request.data.get('created_date_to'):
                        new_created_date_to = datetime.strptime(request.data.get('created_date_to'),
                                                                '%Y-%m-%d') + timedelta(
                            days=1)
                        new_created_date_to_str = new_created_date_to.strftime('%Y-%m-%d')
                        filter_conditions &= Q(
                            CreatedAt__range=[request.data.get('created_date_from'), new_created_date_to_str])
                    if request.data.get('client_id') is not None:
                        filter_conditions &= Q(OrderedCustomerId=request.data.get('client_id')) | Q(
                            BillToCustomerId=request.data.get('client_id')) | Q(
                            DeliveryCustomerId=request.data.get('client_id'))
                    if request.data.get('delivery_date_from') and request.data.get('delivery_date_to'):
                        filter_conditions &= Q(
                            DeliveryDate__range=[request.data.get('delivery_date_from'),
                                                 request.data.get('delivery_date_to')])
                    if request.data.get('search_query') is not None:
                        search_query = request.data.get('search_query')
                        filter_conditions &= Q(
                            Q(ExactOrderNo__icontains=search_query) |
                            Q(OrderedCustomerName__icontains=search_query) |
                            Q(BillToCustomerName__icontains=search_query) |
                            Q(DeliveryCustomerName__icontains=search_query) |
                            Q(ProductName__icontains=search_query)
                        )
                    order_ids = Orders.objects.filter(filter_conditions).values_list('OrderNo', flat=True)
                    unchecked_order_ids = request.data.get('unchecked_order_ids', [])
                    if unchecked_order_ids:  # Check if unchecked_order_ids is present and not empty
                        # Iterate through each value and remove it from all_order_ids if it exists
                        unchecked_order_ids = list(unchecked_order_ids)  # Ensure it's a list
                        filtered_order_ids = [order_id for order_id in order_ids if order_id not in unchecked_order_ids]
                    else:
                        filtered_order_ids = order_ids
                    order_ids = filtered_order_ids
                else:
                    order_ids = request.data.get('order_ids', [])
                    if not order_ids:
                        return Response({
                            'status': 'error',
                            'status_code': 400,
                            'message': 'No order IDs provided.',
                        }, status=400)
            else:
                order_ids = request.data.get('order_ids', [])
                if not order_ids:
                    return Response({
                        'status': 'error',
                        'status_code': 400,
                        'message': 'No order IDs provided.',
                    }, status=400)
            # Attempt to update orders in the database
            orders = Orders.objects.filter(OrderNo__in=order_ids)

            if orders.exists():
                # Update the status_id for the orders
                updated_count = orders.update(StatusId=order_status)
                updated_count=1 
                if order_status == 5:  # order is cancelled so need to update it in BookedSlots table to make the slots free
                    slots = BookedSlots.objects.filter(OrderId__in=order_ids)
                    slots.update(IsDeleted=True)
                    remarks = 'Order Cancelled'
                elif order_status == 3:
                    remarks = 'Order Confirmed'
                for order_id in order_ids:
                    # Log the update in OrderHistory
                    # Get the current UTC time with timezone info
                    # current_utc_time = timezone.now()
                    from datetime import datetime
                    OrderHistory.objects.create(
                        OrderRequestId=order_id,
                        Updation=remarks,
                        UpdatedBy=request.data.get('updated_by'),
                        UpdatedOn=datetime.now(),  # Timestamp of creation,
                        IsDeleted=False
                    )
                if updated_count > 0:
                    return Response(
                        {
                            'status_code': status.HTTP_200_OK,
                            'status': 'success',
                            'message': f"{updated_count} order(s) status successfully updated.",
                            'data': '',
                        },
                        status=status.HTTP_200_OK
                    )
                else:
                    return Response(
                        {
                            'status_code': status.HTTP_404_NOT_FOUND,
                            'status': 'success',
                            'message': "No orders were updated",
                            'data': '',
                        },
                        status=status.HTTP_404_NOT_FOUND
                    )
            else:
                return Response(
                    {
                        'status_code': status.HTTP_404_NOT_FOUND,
                        'status': 'success',
                        'message': "No orders found with the provided order_ids.",
                        'data': '',
                    },
                    status=status.HTTP_404_NOT_FOUND
                )

        # If validation fails, return validation errors
        return Response(
            {
                'status_code': status.HTTP_400_BAD_REQUEST,
                'status': 'success',
                'message': "Invalid input.",
                "errors": serializer.errors,
                'data': '',
            },
            status=status.HTTP_400_BAD_REQUEST
        )


class MarkAsDelivered(APIView):

    def patch(self, request, *args, **kwargs):
        """
        Update the statusId of Orders to 4 for orders with statusId 3
        and DeliveryDate older than today's date.
        """
        today = timezone.now().date()  # Get today's date

        updated_orders = Orders.objects.filter(
            StatusId=3,
            IsDeleted=False
        ).filter(
            Q(DeliveryDate__lt=today) | Q(DeliveryDate__isnull=True, LoadingDate__lt=today)
        )
        # updated_orders = Orders.objects.filter(
        #     StatusId=3,  # Filter for orders with statusId 3
        #     DeliveryDate__lt=today,  # Filter for orders with a DeliveryDate older than today
        #     IsDeleted=False
        # )
        # If no orders match the criteria, return a message indicating so
        if not updated_orders.exists():
            return Response(
                {"message": "No orders found to update."},
                status=status.HTTP_404_NOT_FOUND
            )

        # Loop through each updated order and log the update in OrderHistory
        for order in updated_orders:
            # Create an OrderHistory record for each order being updated
            OrderHistory.objects.create(
                OrderRequestId=order.OrderNo,  
                Updation="Order Delivered",
                UpdatedBy=0,
                UpdatedOn=datetime.now(),
                IsDeleted=False  
            )

        # Update the statusId to 4 for all matching orders
        updated_orders.update(StatusId=4)
        OrderRequests.objects.filter(Id=order.OrderNo).update(IsDelivered=1)
        # Return a response with the number of updated orders
        return Response(
            {
                "message": f"Successfully updated orders and logged the changes in OrderHistory."},
            status=status.HTTP_200_OK
        )


# class GenerateXMLAPIViewOld(APIView):
#     def post(self, request, *args, **kwargs):
#         if request.data.get('all_checked') is not None:
#             all_checked = request.data.get('all_checked')
#             if all_checked == 1:
#                 # Filter conditions setup
#                 filter_conditions = Q(IsDeleted=False)

#                 # Apply additional filters based on request parameters
#                 if request.data.get('status_id') is not None:
#                     filter_conditions &= Q(StatusId=request.data.get('status_id'))
#                 if request.data.get('product_id') is not None:
#                     filter_conditions &= Q(ProductId=request.data.get('product_id'))
#                 if request.data.get('created_date_from') and request.data.get('created_date_to'):
#                     new_created_date_to = datetime.strptime(request.data.get('created_date_to'),
#                                                             '%Y-%m-%d') + timedelta(
#                         days=1)
#                     new_created_date_to_str = new_created_date_to.strftime('%Y-%m-%d')
#                     filter_conditions &= Q(
#                         CreatedAt__range=[request.data.get('created_date_from'), new_created_date_to_str])
#                 if request.data.get('client_id') is not None:
#                     filter_conditions &= Q(OrderedCustomerId=request.data.get('client_id')) | Q(
#                         BillToCustomerId=request.data.get('client_id')) | Q(
#                         DeliveryCustomerId=request.data.get('client_id'))
#                 if request.data.get('delivery_date_from') and request.data.get('delivery_date_to'):
#                     filter_conditions &= Q(
#                         DeliveryDate__range=[request.data.get('delivery_date_from'),
#                                              request.data.get('delivery_date_to')])
#                 if request.data.get('search_query') is not None:
#                     search_query = request.data.get('search_query')
#                     filter_conditions &= Q(
#                         Q(ExactOrderNo__icontains=search_query) |
#                         Q(OrderedCustomerName__icontains=search_query) |
#                         Q(BillToCustomerName__icontains=search_query) |
#                         Q(DeliveryCustomerName__icontains=search_query) |
#                         Q(ProductName__icontains=search_query)
#                     )
#                 order_ids = Orders.objects.filter(filter_conditions).values_list('OrderNo', flat=True)
#                 unchecked_order_ids = request.data.get('unchecked_order_ids', [])
#                 if unchecked_order_ids:  # Check if unchecked_order_ids is present and not empty
#                     # Iterate through each value and remove it from all_order_ids if it exists
#                     unchecked_order_ids = list(unchecked_order_ids)  # Ensure it's a list
#                     filtered_order_ids = [order_id for order_id in order_ids if order_id not in unchecked_order_ids]
#                 else:
#                     filtered_order_ids = order_ids
#                 order_ids = filtered_order_ids
#             else:
#                 order_ids = request.data.get('order_ids', [])
#                 if not order_ids:
#                     return Response({
#                         'status': 'error',
#                         'status_code': 400,
#                         'message': 'No order IDs provided.',
#                     }, status=400)
#         else:
#             order_ids = request.data.get('order_ids', [])
#             if not order_ids:
#                 return Response({
#                     'status': 'error',
#                     'status_code': 400,
#                     'message': 'No order IDs provided.',
#                 }, status=400)
#         # Create an in-memory ZIP file
#         zip_buffer = io.BytesIO()

#         # Use the zipfile module to write into the in-memory zip buffer
#         with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file:
#             for order_id in order_ids:
#                 try:
#                     order_details = Orders.objects.filter(OrderNo=order_id, IsDeleted=False).first()
#                     if order_details:
#                         order_request_serializer = OrderXMLSerializer(order_details, context={'request': request})
#                         if order_request_serializer is not None:
#                             # Create XML structure for the order
#                             root = ET.Element("eExact", xmlns_xsi="http://www.w3.org/2001/XMLSchema-instance",
#                                               xsi_noNamespaceSchemaLocation="eExact-Schema.xsd")
#                             orders = ET.SubElement(root, "Orders")

#                             order_elem = ET.SubElement(orders, "Order", type="V",
#                                                        number=str(order_request_serializer.data['ExactOrderNo']),
#                                                        code="001",
#                                                        partialdelivery="1", confirm="0", invoicemethod="F")

#                             purchase_order_no = OrderRequests.objects.filter(Id=order_id).values_list('PurchaseOrderNo',
#                                                                                                       flat=True).first()
#                             if purchase_order_no:
#                                 ET.SubElement(order_elem, "YourRef").text = purchase_order_no
#                             ET.SubElement(order_elem, "Currency", code="EUR")
#                             ET.SubElement(order_elem, "CalcIncludeVAT")
#                             # Resource Info
#                             # resource = ET.SubElement(order_elem, "Resource",
#                             #                          number=str(order_request_serializer.data['ResourceNo']),
#                             #                          code=str(order_request_serializer.data['ResourceCode']))
#                             # ET.SubElement(resource, "LastName").text = "DE WINNE"
#                             # ET.SubElement(resource, "FirstName").text = "ANN"
#                             # ET.SubElement(resource, "MiddleName")

#                             # OrderedBy Info
#                             ordered_by = ET.SubElement(order_elem, "OrderedBy")
#                             debtor = ET.SubElement(ordered_by, "Debtor",
#                                                    code=str(order_request_serializer.data['OrderedByDebtorCode']),
#                                                    number=str(order_request_serializer.data['OrderedByDebtorCode']),
#                                                    type="C")
#                             ET.SubElement(debtor, "Name").text = str(order_request_serializer.data['OrderedByCompany'])
#                             address = ET.SubElement(ordered_by, "Address")
#                             addressee = ET.SubElement(address, "Addressee")
#                             ET.SubElement(addressee, "Name").text = order_request_serializer.data[
#                                 'OrderedByContactPerson']
#                             ET.SubElement(addressee, "Initials").text = ""
#                             ET.SubElement(addressee, "Title", code="")
#                             ET.SubElement(addressee, "JobDescription").text = order_request_serializer.data[
#                                 'OrderedByJobDescription']
#                             ET.SubElement(address, "AddressLine1").text = order_request_serializer.data[
#                                 'OrderedByAddressLine1']
#                             ET.SubElement(address, "AddressLine2").text = order_request_serializer.data[
#                                 'OrderedByAddressLine2']
#                             ET.SubElement(address, "AddressLine3").text = order_request_serializer.data[
#                                 'OrderedByAddressLine3']
#                             ET.SubElement(address, "PostalCode").text = str(
#                                 order_request_serializer.data['OrderedByPostalCode'])
#                             ET.SubElement(address, "City").text = order_request_serializer.data['OrderedByCity']
#                             ET.SubElement(address, "State",
#                                           code=str(order_request_serializer.data['OrderedByStateCode']))
#                             ET.SubElement(address, "Country",
#                                           code=str(order_request_serializer.data['OrderedByCountryCode']))
#                             ET.SubElement(address, "Phone").text = str(order_request_serializer.data['OrderedByPhone'])
#                             ET.SubElement(address, "Fax").text = str(order_request_serializer.data['OrderedByFax'])
#                             ET.SubElement(address, "Email").text = order_request_serializer.data['OrderedEmail']

#                             # ET.SubElement(ordered_by, "Date").text = str(order_request_serializer.data['DeliveryDate'])

#                             # DeliverTo Info
#                             deliver_to = ET.SubElement(order_elem, "DeliverTo")
#                             debtor = ET.SubElement(deliver_to, "Debtor",
#                                                    code=str(order_request_serializer.data['DeliveryDebtorCode']),
#                                                    number=str(order_request_serializer.data['DeliveryDebtorCode']),
#                                                    type="C")
#                             ET.SubElement(debtor, "Name").text = order_request_serializer.data['DeliveryCompany']
#                             # Add Address Info for DeliverTo
#                             address = ET.SubElement(deliver_to, "Address")
#                             addressee = ET.SubElement(address, "Addressee")
#                             ET.SubElement(addressee, "Name").text = order_request_serializer.data[
#                                 'DeliveryContactPerson']
#                             ET.SubElement(addressee, "Initials").text = ""
#                             ET.SubElement(addressee, "Title", code="-")
#                             ET.SubElement(addressee, "JobDescription").text = order_request_serializer.data[
#                                 'DeliveryJobDescription']
#                             ET.SubElement(address, "AddressLine1").text = order_request_serializer.data[
#                                 'DeliveryAddressLine1']
#                             ET.SubElement(address, "AddressLine2").text = order_request_serializer.data[
#                                 'DeliveryAddressLine2']
#                             ET.SubElement(address, "AddressLine3").text = order_request_serializer.data[
#                                 'DeliveryAddressLine3']
#                             ET.SubElement(address, "PostalCode").text = str(
#                                 order_request_serializer.data['DeliveryPostalCode'])
#                             ET.SubElement(address, "City").text = order_request_serializer.data['DeliveryCity']
#                             ET.SubElement(address, "State",
#                                           code=str(order_request_serializer.data['DeliveryStateCode']))
#                             ET.SubElement(address, "Country",
#                                           code=str(order_request_serializer.data['DeliveryCountryCode']))
#                             ET.SubElement(address, "Phone").text = str(order_request_serializer.data['DeliveryPhone'])
#                             ET.SubElement(address, "Fax").text = str(order_request_serializer.data['DeliveryFax'])
#                             ET.SubElement(address, "Email").text = str(order_request_serializer.data['DeliveryEmail'])

#                             # ET.SubElement(deliver_to, "Date").text = str(order_request_serializer.data['DeliveryDate'])
#                             # InvoiceTo Info (Same as DeliverTo for now)
#                             invoice_to = ET.SubElement(order_elem, "InvoiceTo")
#                             debtor = ET.SubElement(invoice_to, "Debtor",
#                                                    code=str(order_request_serializer.data['InvoiceToDebtorCode']),
#                                                    number=str(order_request_serializer.data['InvoiceToDebtorCode']),
#                                                    type="C")
#                             ET.SubElement(debtor, "Name").text = order_request_serializer.data['InvoiceToCompany']
#                             # Add Address Info for DeliverTo
#                             address = ET.SubElement(invoice_to, "Address")
#                             addressee = ET.SubElement(address, "Addressee")
#                             ET.SubElement(addressee, "Name").text = "E-invoicing"
#                             ET.SubElement(addressee, "Title", code="-")
#                             ET.SubElement(addressee, "JobDescription").text = "--"
#                             ET.SubElement(address, "AddressLine1").text = order_request_serializer.data[
#                                 'InvoiceToAddressLine1']
#                             ET.SubElement(address, "AddressLine2").text = order_request_serializer.data[
#                                 'InvoiceToAddressLine2']
#                             ET.SubElement(address, "AddressLine3").text = order_request_serializer.data[
#                                 'InvoiceToAddressLine3']
#                             ET.SubElement(address, "PostalCode").text = str(
#                                 order_request_serializer.data['InvoiceToPostalCode'])
#                             ET.SubElement(address, "City").text = order_request_serializer.data['InvoiceToCity']
#                             ET.SubElement(address, "State",
#                                           code=str(order_request_serializer.data['InvoiceToStateCode']))
#                             ET.SubElement(address, "Country",
#                                           code=str(order_request_serializer.data['InvoiceToCountryCode']))
#                             ET.SubElement(address, "Phone").text = str(order_request_serializer.data['InvoiceToPhone'])
#                             ET.SubElement(address, "Fax").text = str(order_request_serializer.data['InvoiceToFax'])
#                             ET.SubElement(address, "Email").text = str(order_request_serializer.data['InvoiceToEmail'])

#                             # Warehouse Info
#                             warehouse = ET.SubElement(order_elem, "Warehouse",
#                                                       code=str(order_request_serializer.data['LPCode']))
#                             ET.SubElement(warehouse, "Description").text = order_request_serializer.data['LPName']
#                             warehouse_address = ET.SubElement(warehouse, "Address")
#                             ET.SubElement(warehouse_address, "AddressLine1").text = order_request_serializer.data[
#                                 'LPAddressLine1']
#                             ET.SubElement(warehouse_address, "AddressLine2").text = order_request_serializer.data[
#                                 'LPAddressLine2']
#                             ET.SubElement(warehouse_address, "AddressLine2").text = order_request_serializer.data[
#                                 'LPAddressLine3']
#                             ET.SubElement(warehouse_address, "PostalCode").text = str(
#                                 order_request_serializer.data['LPPostalCode'])
#                             ET.SubElement(warehouse_address, "City").text = order_request_serializer.data['LPCity']
#                             ET.SubElement(warehouse_address, "Country",
#                                           code=str(order_request_serializer.data['LPCountryCode']))
#                             ET.SubElement(warehouse_address, "Phone").text = str(
#                                 order_request_serializer.data['LPPhone'])
#                             ET.SubElement(warehouse_address, "Fax").text = str(order_request_serializer.data['LPFax'])
#                             ET.SubElement(warehouse_address, "Email").text = str(
#                                 order_request_serializer.data['LPEmail'])

#                             # Add the new XML sections for deliverymethos
#                             delivery_method = ET.SubElement(order_elem, 'DeliveryMethod',
#                                                             code=str(order_request_serializer.data['IncoTerm']),
#                                                             type='N')
#                             description = ET.SubElement(delivery_method, 'Description')
#                             description.text = str(order_request_serializer.data['IncoTermDesc'])
#                             # direct_shipping = ET.SubElement(delivery_method, 'DirectShipping')
#                             # direct_shipping.text = '0'
#                             # use_shipping_manifest = ET.SubElement(delivery_method, 'UseShippingManifest')
#                             # use_shipping_manifest.text = '0'

#                             # Add the  XML sections here (Costcenter, Selection, etc.)
#                             costcenter = ET.SubElement(order_elem, "Costcenter",
#                                                        code=str(order_request_serializer.data['CostCenter']))
#                             ET.SubElement(costcenter, "Description").text = order_request_serializer.data[
#                                 'CostCenterDesc']

#                             # transporter section starts
#                             if order_request_serializer.data['TransporterName'] is not None:
#                                 selection = ET.SubElement(order_elem, "Selection",
#                                                           code=str(order_request_serializer.data['TransporterCode']))
#                                 ET.SubElement(selection, "Description").text = str(
#                                     order_request_serializer.data['TransporterName'])
#                             # transporter section ends

#                             # extra_text = ET.SubElement(order_elem, "ExtraText", code="02")
#                             # ET.SubElement(extra_text, "Description").text = "nederlands"
#                             #
#                             # freight = ET.SubElement(order_elem, "Freight")
#                             # ET.SubElement(freight, "Packages").text = "0"
#                             # ET.SubElement(freight, "WeightNet").text = "25000"
#                             # ET.SubElement(freight, "WeightGross").text = "25000"
#                             #
#                             # free_fields = ET.SubElement(order_elem, "FreeFields")
#                             # free_numbers = ET.SubElement(free_fields, "FreeNumbers")
#                             # ET.SubElement(free_numbers, "FreeNumber", number="4").text = "0"
#                             # ET.SubElement(free_numbers, "FreeNumber", number="5").text = "0"
#                             #
#                             # ET.SubElement(order_elem, "ApplyShippingCharges").text = "0"

#                             # Convert the XML to a buffer
#                             tree = ET.ElementTree(root)
#                             xml_buffer = io.BytesIO()
#                             tree.write(xml_buffer, encoding='utf-8', xml_declaration=True)
#                             xml_buffer.seek(0)  # Ensure we are at the start of the buffer

#                             # Add the XML to the zip file, named according to the order ID
#                             zip_file.writestr(f"order_{order_request_serializer.data['ExactOrderNo']}.xml",
#                                               xml_buffer.read())

#                         else:
#                             return Response({
#                                 "status_code": 404,
#                                 "status": "error",
#                                 "message": "No sufficient order details found"
#                             }, status=status.HTTP_404_NOT_FOUND)
#                     else:
#                         return Response({
#                             "status_code": 404,
#                             "status": "error",
#                             "message": "No  order details found"
#                         }, status=status.HTTP_404_NOT_FOUND)
#                 except Exception as e:
#                     # Return a response with an error if there's an issue with processing a particular order
#                     return Response({
#                         'status': 'error',
#                         'status_code': 500,
#                         'message': f"Error processing order ID {order_id}: {str(e)}"
#                     }, status=500)

#         # Ensure the zip buffer is at the start before reading it
#         zip_buffer.seek(0)

#         # Return the zip file as a response with the appropriate headers
#         response = HttpResponse(zip_buffer.read(), content_type='application/zip')
#         response['Content-Disposition'] = 'attachment; filename="orders.zip"'

#         return response


class ServePDFFileView(APIView):
    def get(self, request, filename):
        # Construct the file path
        file_path = os.path.join(settings.QUOTATION_FILE_PATH, filename)
        # Check if the file exists
        if not os.path.exists(file_path):
            return Response({
                "status_code": 404,
                "status": "error",
                "message": "File not found"
            }, status=status.HTTP_404_NOT_FOUND)

        try:
            # Serve the file as a response
            response = FileResponse(open(file_path, 'rb'), content_type='application/pdf')
            response['Content-Disposition'] = f'inline; filename="{filename}"'
            return response
        except Exception as e:
            return Response({
                "status_code": 500,
                "status": "error",
                "message": f"Error serving file: {str(e)}"
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class OrderRequestDetailsAPIView(APIView):
    def post(self, request, *args, **kwargs):
        try:
            # Extract `order_request_id` from the request body
            order_request_id = request.data.get('order_request_id')
            if not order_request_id:
                return Response(
                    {
                        "status_code": 400,
                        "status": "error",
                        "message": "The 'order_request_id' field is required.",
                        "data": None
                    },
                    status=status.HTTP_400_BAD_REQUEST
                )

            # Validate if `order_request_id` is an integer
            if not isinstance(order_request_id, int):
                return Response(
                    {
                        "status_code": 400,
                        "status": "error",
                        "message": "'order_request_id' must be a valid integer.",
                        "data": None
                    },
                    status=status.HTTP_400_BAD_REQUEST
                )

            # Fetch the order using the provided ID
            order = OrderRequests.objects.filter(Id=order_request_id).first()
            if not order:
                return Response(
                    {
                        "status_code": 404,
                        "status": "error",
                        "message": f"Order Request with ID {order_request_id} does not exist.",
                        "data": None
                    },
                    status=status.HTTP_404_NOT_FOUND
                )

            # Serialize the order details
            serializer = OrderRequestSerializer(order, context={'request': request})
            return Response(
                {
                    "status_code": 200,
                    "status": "success",
                    "message": "Order Request details fetched successfully.",
                    "data": serializer.data
                },
                status=status.HTTP_200_OK
            )
        except Exception as e:
            return Response(
                {
                    "status_code": 500,
                    "status": "error",
                    "message": f"An error occurred while processing the request: {str(e)}",
                    "data": None
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )


class UpdateOrderChargesView(APIView):

    def post(self, request, *args, **kwargs):
        # Step 1: Get extra charges from the request data
        extra_charges = request.data.get('extra_charges', [])
        order_request_id = request.data.get('order_request_id')
        if not order_request_id:
            return Response(
                {
                    "status_code": 400,
                    "status": "error",
                    "message": "The 'order_request_id' field is required.",
                    "data": None
                },
                status=status.HTTP_400_BAD_REQUEST
            )
        # Check if any OrderCharges exist for the given OrderNo and mark them as deleted
        order_charges = OrderCharges.objects.filter(OrderNo=order_request_id)
        if order_charges.exists():
            for charge in order_charges:
                charge.IsDeleted = 1
                charge.save()
        if extra_charges:
            for charge in extra_charges:
                OrderCharges.objects.create(
                    OrderNo=order_request_id,
                    ChargeName=charge['charge_name'],
                    ExtraChargeId=charge['extra_charge_id'],
                    Rate=charge['charge_amount'],
                    ArticleCode=charge['ArticleCode'],

                )
            total_charges = OrderCharges.objects.filter(OrderNo=order_request_id, IsDeleted=False).aggregate(
                total_amount=Sum('Rate'),
                charge_count=Count('Rate')
            )
        else:
            total_charges = {
                "total_amount": 0,
                "charge_count": 0
            }
        return Response(
            {
                "status_code": 200,
                "status": "success",
                "message": "Extra charges saved successfully.",
                "data": {
                    "total_extra_charge": total_charges['total_amount'],
                    "count": total_charges['charge_count'],
                    "formatted_extra_charge": convert_to_belgium_format(total_charges['total_amount']),
                }
            },
            status=status.HTTP_200_OK
        )


class DocListView(APIView):
    def post(self, request, *args, **kwargs):
        order_id = request.data.get('order_id')
        if not order_id:
            return Response(
                {
                    "status_code": 400,
                    "status": "error",
                    "message": "The 'order_id' field is required.",
                    "data": None
                },
                status=status.HTTP_400_BAD_REQUEST
            )
        
        try:
            order_request = po_models.OrderRequests.objects.get(Id=order_id)
            client_reference_no = order_request.PurchaseOrderNo
        except ObjectDoesNotExist:
            return Response({
                "status_code": 404,
                "status": "error",
                "message": "Order request not found",
                "data": None
            }, status=status.HTTP_404_NOT_FOUND)

        order_details = Orders.objects.filter(OrderNo=order_id, IsDeleted=False).first()
        if order_details:
            # if order_details.LoadPoint == 'PVS':
            loadlist_serializer = LoadListSerializer(order_details, context={'request': request})
            # Format dates
            loading_date = datetime.strptime(loadlist_serializer.data['LoadingDate'], "%Y-%m-%d").strftime("%d/%m/%Y")
            delivery_date = datetime.strptime(loadlist_serializer.data['DeliveryDate'], "%Y-%m-%d").strftime("%d/%m/%Y") if loadlist_serializer.data['DeliveryDate'] else ""
            filling_date = datetime.strptime(loadlist_serializer.data['FillingDate'], "%Y-%m-%d").strftime("%d/%m/%Y") if loadlist_serializer.data['FillingDate'] else ""

            if loadlist_serializer.data['IsADR'] == 'ADR':
                is_adr = 1
                productname_with_uncode = loadlist_serializer.data['ProductNameDutch']
            else:
                is_adr = 0
                productname_with_uncode = ''
            if loadlist_serializer.data['IncoTerm'] == 'FCA' or loadlist_serializer.data['IncoTerm'] == 'EXW':
                loadlist_city = loadlist_serializer.data['LoadPointCity']
            else:
                loadlist_city = loadlist_serializer.data['ShipToCity']

            product_id = loadlist_serializer.data['ProductId']
            
            product_data = fetch_data.get_product_data(product_id)
            
            # Prepare data for the frontend
            response_data = {
                'transporter_name': loadlist_serializer.data['TransporterName'],
                'loading_point': loadlist_serializer.data['LoadingSlot'],
                'loading_date': loading_date,
                'loading_time': loadlist_serializer.data['LoadingTime'],
                'client_name': loadlist_serializer.data['CustomerName']+ " "+loadlist_serializer.data['ShipToCity'],
                'ship_to_city': loadlist_city,
                'filling_date': filling_date, 
                'delivery_date': delivery_date,
                'delivery_time': loadlist_serializer.data['DeliveryTimeInterval'],
                'order_no': loadlist_serializer.data['ExactOrderNo'],
                'product': loadlist_serializer.data['ProductName'],
                'article_code': loadlist_serializer.data['ArticleCode'],
                'quantity': loadlist_serializer.data['Quantity'],
                'additional_remarks': loadlist_serializer.data['TNC'],
                'po_number': loadlist_serializer.data['PurchaseOrderNo'],
                'load_reference': loadlist_serializer.data['LoadReference'],
                'inco_term':loadlist_serializer.data['IncoTerm'],
                'is_adr':is_adr,
                'productname_with_uncode':productname_with_uncode,
                'notes': loadlist_serializer.data['Notes'],
                'loading_slot':loadlist_serializer.data['LoadPoint'],
                'additional_notes':loadlist_serializer.data['Remarks'],
                'station_reference':loadlist_serializer.data['LoadingStationReference'],
                'record_url':loadlist_serializer.data['InstructionMasterURL'],
                # 'instructions':loadlist_serializer.data['Instructions'],
            }

            if product_data['packaging'].lower()=='bulk':
                packaging = product_data['packaging'].capitalize()
                package_data = {}
            else:
                packaging = product_data['packaging'].capitalize()
                package_data = purchase_utils.get_quantity_summary(order_request)
            
            response_data['packaging'] = packaging
            response_data['packaging_data'] = package_data

            # Return data as JSON instead of generating a PDF
            return Response(
                {
                    "status_code": 200,
                    "status": "success",
                    "message": "LoadList data retrieved successfully",
                    "data": response_data
                },
                status=status.HTTP_200_OK
            )
        else:
            return Response(
                {
                    'status_code': status.HTTP_404_NOT_FOUND,
                    'status': "error",
                    'message': "No orders found",
                    'data': None,
                },
                status=status.HTTP_404_NOT_FOUND
            )


def check_coc_needed(auth_token, ArticleCode, IncoTerm, ShipToCode):
    api_url = settings.DELIVERY_API_URL + "terms_conditions/"
    headers = {
        'x-api-key': os.getenv('API_KEY'),
        'x-content-type': 'application/json',
        'x-auth-token': auth_token,
    }
    payload = {"article_code": ArticleCode,
               "inco_term": IncoTerm,
               "ship_to_code": ShipToCode}
    try:
        response = requests.post(api_url, json=payload, headers=headers)
        if response.status_code == 200:
            data = response.json()
            is_coc_needed = data.get('data', {}).get('COCNeeded', [])
            return is_coc_needed
        else:
            return 1
    except requests.RequestException as e:
        print(f"An error occurred: {e}")
        return None


class CocView(APIView):
    def post(self, request, *args, **kwargs):
        order_id = request.data.get('order_id')
        if not order_id:
            return Response(
                {
                    "status_code": 400,
                    "status": "error",
                    "message": "The 'order_id' field is required.",
                    "data": None
                },
                status=status.HTTP_400_BAD_REQUEST
            )

        order_details = Orders.objects.filter(OrderNo=order_id, IsDeleted=False).first()
        if order_details:
            loadlist_serializer = LoadListSerializer(order_details, context={'request': request})
            # is_coc_needed = check_coc_needed(request.headers.get('x-auth-token'),
            #                                  loadlist_serializer.data['ArticleCode'],
            #                                  loadlist_serializer.data['IncoTerm'],
            #                                  loadlist_serializer.data['ShipToCode'])
            is_coc_needed = 1
            if is_coc_needed:
                # Format dates
                loading_date = datetime.strptime(loadlist_serializer.data['LoadingDate'], "%Y-%m-%d").strftime(
                    "%d/%m/%Y")
                # Prepare data for the frontend
                response_data = {
                    'client_name': loadlist_serializer.data['CustomerName'],
                    'product': loadlist_serializer.data['FormattedProductName'],
                    'article_code': loadlist_serializer.data['ArticleCode'],
                    'load_reference': loadlist_serializer.data['ExactOrderNo'] + '/1',
                    'po_number': loadlist_serializer.data['PurchaseOrderNo'],
                    'order_no': loadlist_serializer.data['ExactOrderNo'],
                    'loading_date': loading_date,
                    'quantity': loadlist_serializer.data['Quantity'],
                    'coc_quality_statement': 'We hereby certify that the quality of the above mentioned product complies with the required specifications as described in our Technical Data Sheet.'
                }
                # special coc if ordered customer is
                if loadlist_serializer.data['ShipToCode'] == 2148:
                    response_data['coc_quality_statement'] = "We hereby certify that the quality of the above mentioned product complies with the required specifications mentioned in Algist Bruggeman’s raw material sheet GKD003v9."

                # Return data as JSON instead of generating a PDF
                return Response(
                    {
                        "status_code": 200,
                        "status": "success",
                        "message": "COC data retrieved successfully",
                        "data": response_data
                    },
                    status=status.HTTP_200_OK
                )
            else:
                return Response(
                    {
                        "status_code": 400,
                        "status": "error",
                        "message": "No Conformity Certificate is needed for this product",
                        "data": None
                    },
                    status=status.HTTP_400_BAD_REQUEST
                )
        else:
            return Response(
                {
                    'status_code': status.HTTP_404_NOT_FOUND,
                    'status': "error",
                    'message': "No orders found",
                    'data': None,
                },
                status=status.HTTP_404_NOT_FOUND
            )


def extract_string(input_string):
    # Use regex to remove number at the start of the string
    cleaned_string = re.sub(r'^\d+\s', '', input_string)
    return cleaned_string


class TransporterRequestDataView(APIView):
    """Everything the transporter availability and price request screen needs.

    One call rather than several, because the screen cannot render usefully
    until it has all of it: which carriers to offer, which were already asked,
    the addresses each would be reached on, and the order details that make up
    the mail. Replies are not handled here - they go to the sales mailbox and
    the planner types the chosen price into the order by hand.
    """

    def _fetch(self, request, api_url, payload, key):
        """Call another service the way the serializers already do."""
        headers = {
            'x-api-key': os.getenv('API_KEY'),
            'x-content-type': 'application/json',
        }
        auth_token = request.headers.get('x-auth-token', None)
        if auth_token:
            headers['x-auth-token'] = auth_token
        try:
            response = requests.post(api_url, json=payload, headers=headers)
            if response.status_code == 200:
                return response.json().get('data', {}).get(key, None)
            return None
        except requests.RequestException as e:
            print(f"An error occurred while fetching data: {e}")
            return None

    def post(self, request, *args, **kwargs):
        order_id = request.data.get('order_id')
        if not order_id:
            return Response(
                {
                    "status_code": 400,
                    "status": "error",
                    "message": "The 'order_id' field is required.",
                    "data": None
                },
                status=status.HTTP_400_BAD_REQUEST
            )

        order_details = Orders.objects.filter(OrderNo=order_id, IsDeleted=False).first()
        if not order_details:
            return Response(
                {
                    "status_code": 404,
                    "status": "error",
                    "message": "Order not found.",
                    "data": None
                },
                status=status.HTTP_404_NOT_FOUND
            )

        try:
            serializer = TransportMailSerializer(order_details, context={'request': request})
            data = serializer.data
            order_request = OrderRequests.objects.filter(Id=order_id).first()

            # ---- the carriers to offer -------------------------------------
            # Same source the Transporter dropdown uses, so the request cannot
            # offer a carrier the planner could not then pick.
            transporters = self._fetch(
                request,
                settings.DELIVERY_API_URL + "get_transporters_for_product/",
                # Same payload the Transporter dropdown sends. delivery_address_id
                # is the AddressMaster row on the order, not the Exact address id -
                # the view looks up a city mapping from it and cannot handle a miss.
                # packaging_type is literally "bulk" there for every order, packed
                # included, so it is matched rather than guessed at.
                {
                    "product_id": order_details.ProductId,
                    "load_point_id": data.get('LoadPointId'),
                    "delivery_address_id": (
                        order_request.DeliverTo if order_request else None
                    ),
                    "packaging_type": "bulk",
                    "loading_date": data.get('LoadingDate'),
                },
                # GetTransporterFromProductView nests the carriers under "list",
                # alongside recommended_transporter_id.
                'list'
            ) or []

            transporter_ids = [
                t.get('TransporterId') for t in transporters if t.get('TransporterId')
            ]

            # ---- addresses, in one call rather than one per carrier ---------
            mail_ids_by_transporter = {}
            without_mail_ids = []
            if transporter_ids:
                bulk = self._fetch(
                    request,
                    settings.DELIVERY_API_URL + "get_transporter_mail_ids_bulk/",
                    {
                        "transporter_ids": transporter_ids,
                        "product_category": data.get('ProductCategory'),
                    },
                    'mail_ids_by_transporter'
                )
                mail_ids_by_transporter = bulk or {}

            # ---- who has already been asked --------------------------------
            already_sent = {
                row.transporter_id: row.request_sent_at
                for row in po_models.OrderTransporterRequests.objects.filter(
                    order_request_id=order_details.OrderNo, is_deleted=False
                )
            }

            transporter_rows = []
            for t in transporters:
                tid = t.get('TransporterId')
                mail_ids = mail_ids_by_transporter.get(str(tid), [])
                if not mail_ids:
                    without_mail_ids.append(tid)
                sent_at = already_sent.get(tid)
                transporter_rows.append({
                    "transporter_id": tid,
                    "transporter": t.get('Transporter'),
                    "transporting_price": t.get('TransportingPrice'),
                    "frequency": t.get('Frequency'),
                    # These are the bcc addresses. A carrier with none cannot be
                    # asked, so the screen should show it but not let it be
                    # selected, rather than dropping it silently.
                    "mail_ids": mail_ids,
                    "can_be_requested": bool(mail_ids),
                    "request_sent_at": sent_at,
                    "already_sent": sent_at is not None,
                })

            # ---- the mail content ------------------------------------------
            subject = (
                f"Transport availability & price request   "
                f"{data.get('CustomerName')} - {data.get('ShipToCity')}   "
                f"{data.get('FormattedProductName')} - {data.get('ExactOrderNo')}"
            )

            # A saved draft wins over the generated subject, the same way the
            # transport instruction mail behaves.
            body = None
            draft = po_models.EmailDraft.objects.filter(
                order_request_id=order_id, is_deleted=False,
                email_type='transporter_request'
            ).first()
            if draft:
                body = draft.body
                if draft.subject:
                    subject = draft.subject

            # Cc is the internal side of the mail: the standing distribution
            # list plus whoever is sending it. The carriers themselves are
            # never in to or cc - they go in bcc, chosen on the screen.
            default_cc = os.getenv('TRANSPORTER_DEFAULT_CC_EMAILS')
            cc_emails = default_cc.split(',') if default_cc else []
            portal_user_mail = data.get('PortalUserMailId')
            if portal_user_mail:
                cc_emails.append(portal_user_mail)
            cc_emails = list(set(cc_emails))

            if data.get('DriverLanguages'):
                remarks = (
                    "Please note that each driver must be able to understand "
                    f"and speak {data.get('DriverLanguages')}"
                )
            else:
                remarks = ''

            order_block = {
                "exact_order_no": data.get('ExactOrderNo'),
                "purchase_order_no": data.get('PurchaseOrderNo'),
                "customer_name": data.get('CustomerName'),
                "product_name": data.get('ProductName'),
                "formatted_product_name": data.get('FormattedProductName'),
                "product_category": data.get('ProductCategory'),
                "article_code": data.get('ArticleCode'),
                "is_adr": data.get('IsADR'),
                "quantity": data.get('Quantity'),
                "dimension": data.get('dimension'),
                "package_details": data.get('product_data'),
                "incoterm": data.get('IncoTerm'),
                # route, as the carrier needs to price it
                "load_point": data.get('LoadPoint'),
                "load_point_city": data.get('LoadPointCity'),
                "load_point_address_line1": data.get('LoadPointAddressLine1'),
                "load_point_address_line2": data.get('LoadPointAddressLine2'),
                "ship_to_city": data.get('ShipToCity'),
                "customer_address": data.get('CustomerAddress'),
                "loading_date": data.get('LoadingDate'),
                "loading_time": data.get('LoadingTime'),
                "delivery_date": data.get('DeliveryDate'),
                "delivery_time_interval": data.get('DeliveryTimeInterval'),
                # Route, package counts, pallet size, weights and the ADR
                # identifiers - what a carrier actually needs to quote on. Kept
                # in its own block so the mail can be built from it directly.
                "quote": (
                    fetch_data.get_transport_quote_details(order_request)
                    if order_request else {}
                ),
            }

            return Response(
                {
                    "status_code": 200,
                    "status": "success",
                    "message": "Transporter request data fetched successfully.",
                    "data": {
                        "order": order_block,
                        "email": {
                            "subject": subject,
                            # None when nothing has been drafted yet: the screen
                            # then builds the body from the order block.
                            "body": body,
                            "has_draft": draft is not None,
                            # to stays empty by design - the send endpoint
                            # rejects a transporter request that fills it.
                            "to": [],
                            "cc": cc_emails,
                            # No default_attachments here on purpose. The PVS
                            # safety requirements ride with the transporter
                            # instruction mail, sent to the carrier that won the
                            # job - not with a quotation request that goes to
                            # every carrier being asked.
                            "sender_name": data.get('PortalUserName'),
                            "sender_mail_id": portal_user_mail,
                            "remarks": remarks,
                            "is_adr": data.get('IsADR'),
                            "product_name_dutch": data.get('ProductNameDutch'),
                        },
                        "transporters": transporter_rows,
                        "transporters_without_mail_ids": without_mail_ids,
                        "sent_count": sum(1 for r in transporter_rows if r["already_sent"]),
                    }
                },
                status=status.HTTP_200_OK
            )

        except Exception as e:
            return Response(
                {
                    "status_code": 500,
                    "status": "error",
                    "message": "An error occurred while fetching the transporter request data.",
                    "error": str(e),
                    "data": None
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )


class _DocumentMailInfoBase(APIView):
    """Shared plumbing for the packed-goods document emails."""

    def get_order(self, order_id):
        return Orders.objects.filter(OrderNo=order_id, IsDeleted=False).first()

    def get_container(self, order_id):
        return po_models.OrderContainerDetails.objects.filter(
            order_request_id=order_id, IsDeleted=False
        ).first()

    def standing_cc(self, request):
        """The internal addresses copied on every document email: the planner
        sending it and the sales mailbox.

        Not the transporter default list - that is for carrier mails, and these
        go to shipping agents, warehouses and customs.
        """
        cc = ['sales@pvs.be']
        planner = getattr(request, 'login_user_email', None)
        if planner:
            cc.append(planner)
        return sorted({address.strip() for address in cc if address.strip()})

    def rows(self, pairs):
        """The detail lines, as a table so the colons line up in any client."""
        cells = ''.join(
            '<tr><td style="padding:2px 12px 2px 0;">{}</td>'
            '<td style="padding:2px 0;">: {}</td></tr>'.format(label, value or '')
            for label, value in pairs
        )
        return '<table style="border-collapse:collapse;">{}</table>'.format(cells)

    def fail(self, message, code):
        return Response(
            {"status_code": code, "status": "error", "message": message, "data": None},
            status=code,
        )


class ShippingAgentMailInfoView(_DocumentMailInfoBase):
    """Ask the agency when an empty container is available.

    Only a sea order needs one, so a road order gets not_needed rather than a
    composer with nothing to say.
    """

    def post(self, request, *args, **kwargs):
        order_id = request.data.get('order_id')
        if not order_id:
            return self.fail("The 'order_id' field is required.", 400)

        order = self.get_order(order_id)
        if not order:
            return self.fail("Order not found.", 404)

        data = TransportMailSerializer(order, context={'request': request}).data
        order_request = OrderRequests.objects.filter(Id=order_id).first()
        mode = order_request.transport_mode if order_request else None

        if (mode or '').lower() != 'ship':
            return Response({
                "status_code": 200, "status": "success",
                "message": "Not required for this order.",
                "data": {"not_needed": "Not needed - this order travels by {}.".format(mode or 'Truck')},
            }, status=status.HTTP_200_OK)

        container = self.get_container(order_id)
        port = container.port_of_loading if container else ''

        # the agency chosen on the order, and where to reach it
        to_mails = []
        if container and container.shipping_agency_id:
            api_url = settings.DELIVERY_API_URL + "shipping_agencies/"
            try:
                response = requests.get(api_url, headers={
                    'x-api-key': os.getenv('API_KEY'),
                    'x-auth-token': request.headers.get('x-auth-token', ''),
                })
                if response.status_code == 200:
                    for row in response.json().get('data', []):
                        if row.get('Id') == container.shipping_agency_id:
                            to_mails = row.get('MailIds', [])
                            break
            except requests.RequestException as e:
                print(f"Shipping agencies not reachable: {e}")

        body = (
            '<div>Good afternoon,</div><br/>'
            '<div>We have the following shipment to send by sea and would like to '
            'know when an empty container is available.</div><br/>'
            + self.rows([
                ('Goods', data.get('ProductName')),
                ('Packaging', data.get('dimension')),
                ('Quantity', data.get('Quantity')),
                ('Port', port),
                ('Consignee', data.get('DeliveryCustomerName') or data.get('CustomerName')),
                ('Required around', data.get('LoadingDate')),
            ])
            + '<br/><div>Could you let us know on which date and time the empty '
              'container can be collected, at which exact location within the port, '
              'and by when it has to be returned?</div><br/>'
        )

        return Response({
            "status_code": 200, "status": "success",
            "message": "Shipping agent mail info fetched successfully.",
            "data": {
                "not_needed": None,
                "subject": "Empty container request - Order {}".format(data.get('ExactOrderNo') or ''),
                "body": body,
                "to": to_mails,
                "cc": self.standing_cc(request),
            },
        }, status=status.HTTP_200_OK)


# ERC need PVS's own purchase order before they accept the goods, and Order Pro
# cannot produce one. So the warehouse mail to ERC must carry a PDF the planner
# made elsewhere. One definition, read by the info view and the send view.
PURCHASE_ORDER_STATION = 'ERC'
PURCHASE_ORDER_REQUIREMENT = {
    "key": "purchase_order",
    "label": "Purchase order",
    "message": "A purchase order document is required for ERC. Please attach "
               "it before sending.",
}


def requires_purchase_order(order):
    """Whether this order loads at ERC, judged as WarehouseMailInfoView does."""
    if not order:
        return False
    station = (getattr(order, 'LoadingSlot', '') or
               getattr(order, 'LoadPoint', '') or '').strip()
    return station == PURCHASE_ORDER_STATION


class WarehouseMailInfoView(_DocumentMailInfoBase):
    """Ask a third party warehouse to arrange the loading.

    Only for a station that is not a PVS site. ERC schedule their own slot, so
    the request names no time for them.
    """

    THIRD_PARTY = ('Katoen Natie', 'ERC')

    def post(self, request, *args, **kwargs):
        order_id = request.data.get('order_id')
        if not order_id:
            return self.fail("The 'order_id' field is required.", 400)

        order = self.get_order(order_id)
        if not order:
            return self.fail("Order not found.", 404)

        data = TransportMailSerializer(order, context={'request': request}).data
        station = order.LoadingSlot if hasattr(order, 'LoadingSlot') else ''
        station = station or data.get('LoadPoint') or ''

        if station not in self.THIRD_PARTY:
            return Response({
                "status_code": 200, "status": "success",
                "message": "Not required for this order.",
                "data": {"not_needed": "Loading station is {} - no third party warehouse "
                                       "arrangement is needed for this station.".format(station or 'a PVS station')},
            }, status=status.HTTP_200_OK)

        is_erc = station == 'ERC'
        order_request = OrderRequests.objects.filter(Id=order_id).first()
        to_mails = []
        if order_request:
            address = fetch_data.get_loadpoint_email(order_request.LoadPointId)
            if address:
                to_mails = [address]

        loading = ('To be scheduled directly with ERC' if is_erc
                   else '{} {}'.format(data.get('LoadingDate') or '',
                                       data.get('LoadingTime') or '').strip())

        body = (
            '<div>Good afternoon,</div><br/>'
            '<div>Please arrange the loading of the following order at your '
            'facility:</div><br/>'
            + self.rows([
                ('Order', data.get('ExactOrderNo')),
                ('Product', data.get('ProductName')),
                ('Packaging', data.get('dimension')),
                ('Quantity', data.get('Quantity')),
                ('Requested loading', loading),
                ('Customer', data.get('DeliveryCustomerName') or data.get('CustomerName')),
            ])
            + '<br/><div>Please find the attached documents.</div><br/>'
        )

        return Response({
            "status_code": 200, "status": "success",
            "message": "Warehouse mail info fetched successfully.",
            "data": {
                "not_needed": None,
                "subject": "Loading Arrangement Request - Order {}".format(data.get('ExactOrderNo') or ''),
                "body": body,
                "to": to_mails,
                "cc": self.standing_cc(request),
                # Files the planner must attach before this mail can go.
                "required_attachments": (
                    [PURCHASE_ORDER_REQUIREMENT] if is_erc else []
                ),
            },
        }, status=status.HTTP_200_OK)


class CustomsMailInfoView(_DocumentMailInfoBase):
    """Ask the customs agent to draw up the export document.

    Written in Dutch: the agents are Belgian and the existing correspondence with
    them is in Dutch.

    No recipient is filled in. The agent is chosen per shipment and route, so
    there is no address on file to default to - the planner types it in.

    Two orders do not need one. ERC handle the customs paperwork themselves when
    they load, so it belongs in their request instead; and an order staying
    inside the EU is not an export at all.
    """

    def post(self, request, *args, **kwargs):
        order_id = request.data.get('order_id')
        if not order_id:
            return self.fail("The 'order_id' field is required.", 400)

        order = self.get_order(order_id)
        if not order:
            return self.fail("Order not found.", 404)

        data = TransportMailSerializer(order, context={'request': request}).data
        station = (order.LoadingSlot if hasattr(order, 'LoadingSlot') else '') or ''

        if station == 'ERC':
            return Response({
                "status_code": 200, "status": "success",
                "message": "Not required for this order.",
                "data": {"not_needed": "Customs document not needed for ERC."},
            }, status=status.HTTP_200_OK)

        # AddressMaster.HasOriginStatement on the delivery address, read the same
        # way OrderProcessInitiateView reads it. It replaced an Odoo field called
        # is_outside_european_union, so a set flag means the goods leave the EU.
        order_request = OrderRequests.objects.filter(Id=order_id).first()
        needs_customs = False
        country = ''
        if order_request and order_request.DeliverTo:
            address = fetch_data.get_address_data(order_request.DeliverTo)
            needs_customs = bool(address and address.get('has_origin_statement'))
            country = (address or {}).get('country') or ''

        if not needs_customs:
            return Response({
                "status_code": 200, "status": "success",
                "message": "Not required for this order.",
                "data": {"not_needed": "Not needed - the customer is within the EU, so the "
                                       "shipment is not an export."},
            }, status=status.HTTP_200_OK)

        # What is being loaded. The samples count packages ("2 IBC\'s",
        # "7 mobiele tankcontainers"), not tonnes, so the package count leads and
        # the MT quantity is only used when there is no count to give.
        load = '{} {}'.format(order.no_of_packings or '', data.get('Packaging') or '').strip()
        if not order.no_of_packings:
            load = '{} MT {}'.format(data.get('Quantity') or '',
                                     data.get('Packaging') or '').strip()
        product = data.get('ProductName') or ''

        # Both samples name the absence of ADR and say nothing when the goods are
        # ADR, so that is what is reproduced here rather than a rule of our own.
        adr = '' if data.get('IsADR') else ' (geen ADR)'

        # Under EUR 6000 an origin declaration on the invoice replaces a EUR.1,
        # so the agent is told. A zero total means the order carries no price
        # yet - claiming a value we do not have would be worse than saying
        # nothing, so the clause is simply left out.
        value = order.TotalPrice or 0
        value_clause = ('; en hebben een waarde &lt; 6000 EUR'
                        if 0 < value < 6000 else '')

        blank = '<b>[ in te vullen ]</b>'

        body = (
            '<div>Goedemiddag,</div><br/>'
            '<div>Op {date} zullen er {load} {product}{adr} bij ons geladen worden '
            'voor levering in {country} (condities: {incoterm} {loadpoint}) - '
            'Klant: {customer}.</div>'
            '<div>De goederen zijn van Belgische origine; door ons '
            '(PVS Chemicals Gent) geproduceerd{value}.</div><br/>'
            '<div>De originele factuur (met oorsprongsverklaring, naam, '
            'handtekening, stempel en datum) kunnen we pas opmaken en doorsturen '
            'na afhaling van de goederen. Zie paklijst in bijlage.</div><br/>'
            '<div>Kunnen jullie de nodige douanedocumenten (EUA, EUR1 en T2) '
            'opmaken aub?</div><br/>'
            '<div><b>[ kies \u00e9\u00e9n regel en verwijder de andere ]</b></div>'
            '<div>Wij zullen dit zelf printen, zodat de chauffeur zich niet meer '
            'bij jullie dient aan te melden.</div>'
            '<div>De chauffeur zal zich rechtstreeks bij jullie melden. Graag '
            'jullie referentie.</div><br/>'
            '<div>Hierbij de nodige gegevens:</div>'.format(
                date=data.get('LoadingDate') or '',
                load=load,
                product=product,
                adr=adr,
                country=country or blank,
                incoterm=data.get('IncoTerm') or '',
                loadpoint=data.get('LoadPointCity') or data.get('LoadPoint') or '',
                customer=data.get('DeliveryCustomerName') or data.get('CustomerName') or '',
                value=value_clause,
            )
            + self.rows([
                ('Exit EC border / Office of transit', blank),
                ('Customs office / Office of destination', blank),
                ('Agent', blank),
            ])
            + '<br/><div>Alvast bedankt!</div>'
              '<div><b>[ alleen bij een EUR1 - anders verwijderen ]</b> NIET '
              'VERGETEN OM EEN COPY VAN HET EUR1 DOCUMENT TE NEMEN EN NAAR ONS TE '
              'MAILEN!</div><br/>'
        )

        return Response({
            "status_code": 200, "status": "success",
            "message": "Customs mail info fetched successfully.",
            "data": {
                "not_needed": None,
                "subject": "Douanedocument aanvraag - Order {}".format(
                    data.get('ExactOrderNo') or ''),
                "body": body,
                "to": [],
                "cc": self.standing_cc(request),
            },
        }, status=status.HTTP_200_OK)


class TransportMailView(APIView):
    def post(self, request, *args, **kwargs):
        order_id = request.data.get('order_id')
        if not order_id:
            return Response(
                {
                    "status_code": 400,
                    "status": "error",
                    "message": "The 'order_id' field is required.",
                    "data": None
                },
                status=status.HTTP_400_BAD_REQUEST
            )

        order_details = Orders.objects.filter(OrderNo=order_id, IsDeleted=False).first()
        if order_details:
            transportmail_serializer = TransportMailSerializer(order_details, context={'request': request})
            if transportmail_serializer.data['IncoTerm'] != 'FCA' and transportmail_serializer.data['IncoTerm'] != 'EXW':
                # Format dates
                loading_date = datetime.strptime(transportmail_serializer.data['LoadingDate'], "%Y-%m-%d").strftime(
                    "%d/%m/%Y")
                delivery_date = datetime.strptime(transportmail_serializer.data['DeliveryDate'], "%Y-%m-%d").strftime(
                    "%d/%m/%Y") if transportmail_serializer.data['DeliveryDate'] else ""
                if (transportmail_serializer.data['LoadPoint'] == 'PVS'):
                    subject = f"Transport   {transportmail_serializer.data['CustomerName']} - {transportmail_serializer.data['ShipToCity']}   {transportmail_serializer.data['FormattedProductName']} - {transportmail_serializer.data['ExactOrderNo']}"
                else:
                    subject = f"Transport   {transportmail_serializer.data['CustomerName']} - {transportmail_serializer.data['ShipToCity']}    {transportmail_serializer.data['FormattedProductName']} {transportmail_serializer.data['LoadPoint']} - {transportmail_serializer.data['ExactOrderNo']}"

                body = None

                emaildraft = po_models.EmailDraft.objects.filter(
                    order_request_id=order_id, is_deleted=False, email_type='transporter').first()
                if emaildraft:
                    body = emaildraft.body
                    subject = emaildraft.subject

                if transportmail_serializer.data['DriverLanguages'] != '':
                    remarks = f"Please note that each driver must be able to understand and speak {transportmail_serializer.data['DriverLanguages']}"
                else:
                    remarks = ''

                if transportmail_serializer.data['IsADR'] == 'ADR':
                    is_adr = 1
                    productname_with_uncode = transportmail_serializer.data['ProductNameDutch']
                else:
                    is_adr = 0
                    productname_with_uncode = ''
                default_cc = os.getenv('TRANSPORTER_DEFAULT_CC_EMAILS')
                cc_emails = default_cc.split(',') if default_cc else []
                
                second_email = transportmail_serializer.data['PortalUserMailId']
                if second_email:
                    cc_emails.append(second_email)
                cc_emails = list(set(cc_emails))
                # record = OrderFiles.objects.filter(
                #     OrderId=order_id,
                #     Type='UnloadingInstruction',
                #     IsDeleted=False
                # ).values('FileName').first()
                # if record:
                #     existing_pdf = settings.PO_API_URL+"serve_doc/"+record['FileName']
                #     unload_data = ''
                # else:
                # unload_data = UnloadInstructions.objects.filter(ArticleCode=transportmail_serializer.data['ArticleCode'],ExactERPAddressId=transportmail_serializer.data['ShipToCode'],IncoTerm=transportmail_serializer.data['IncoTerm'],LoadPointId=transportmail_serializer.data['LoadPointId'],IsDeleted=0).values_list('Instructions', 'Color')
                #     existing_pdf = ''

                
                # unload_data = UnloadInstructions.objects.filter(
                #     ArticleCode=transportmail_serializer.data['ArticleCode'],
                #     ExactERPAddressId=transportmail_serializer.data['ShipToCode'],
                #     IncoTerm=transportmail_serializer.data['IncoTerm'],
                #     LoadPointId=transportmail_serializer.data['LoadPointId'],
                #     IsDeleted=0
                # ).values_list('Instructions', 'Color','IsImageReq')
                # formatted_unload_data = [{"text": instruction, "color": color,"is_image_req":is_image_req} for instruction, color ,is_image_req in unload_data]

                formatted_unload_data = purchase_utils.get_unload_instructions(
                    transportmail_serializer.data['ArticleCode'], 
                    transportmail_serializer.data['IncoTerm'], transportmail_serializer.data['ShipToCode'], 
                    transportmail_serializer.data['LoadPointId'],
                    transportmail_serializer.data['BillToCode'])


                response_data = {
                    'to': transportmail_serializer.data['TransportContactHistory']['to_mails'],
                    'cc': cc_emails,
                    'subject': subject,
                    'email_body':body, 
                    'product': transportmail_serializer.data['FormattedProductName'],
                    'packaging': transportmail_serializer.data['Packaging'],
                    'packaging_info': purchase_utils.get_PackagingInfo(order_id),
                    'quantity': float(transportmail_serializer.data['Quantity']) if transportmail_serializer.data['Quantity'] is not None else None,
                    'client_name': transportmail_serializer.data['CustomerName'],
                    'client_address': transportmail_serializer.data['CustomerAddress'],
                    'client_reference': transportmail_serializer.data[
                        'PurchaseOrderNo'] if transportmail_serializer.data.get('PurchaseOrderNo') else 'N/A',
                    'reference': transportmail_serializer.data['ExactOrderNo'],
                    'loading_at': transportmail_serializer.data['LoadPoint'] + ' - ' + transportmail_serializer.data[
                        'LoadPointCity'],
                    'loading_date': loading_date,
                    'loading_time': transportmail_serializer.data['LoadingTime'],
                    'delivery_date': delivery_date,
                    'delivery_time': transportmail_serializer.data['DeliveryTimeInterval'],
                    'additional_remarks': remarks,
                    'triggered_by': transportmail_serializer.data['PortalUserName'],
                    'is_adr': is_adr,
                    'productname_with_uncode': productname_with_uncode,
                    'delivery_city': transportmail_serializer.data['ShipToCity'],
                    'transporter_id': transportmail_serializer.data['TransporterId'],
                    'loadpoint_address_line1':transportmail_serializer.data['LoadPointAddressLine1'],
                    'loadpoint_address_line2': transportmail_serializer.data['LoadPointAddressLine2'],
                    'instructions':formatted_unload_data,
                    'article_code':transportmail_serializer.data['ArticleCode'],
                    'inco_term':transportmail_serializer.data['IncoTerm'],
                    'loadpoint_id':transportmail_serializer.data['LoadPointId'],
                    'ship_to_code': transportmail_serializer.data['ShipToCode'],
                    'container_no': transportmail_serializer.data['ContainerNo'],
                    'dimension': transportmail_serializer.data['dimension'],
                    'is_container_required': transportmail_serializer.data['IsContainerRequired'],
                    'is_delivery_date_required': transportmail_serializer.data['IsDeliveryDateRequired'],
                    'station_reference': transportmail_serializer.data['LoadingStationReference'],
                    'need_unload_reference': transportmail_serializer.data['NeedUnLoadReference'],
                    'default_attachments': transportmail_serializer.data['DefaultAttachments'],
                    'bill_to_code': transportmail_serializer.data['BillToCode'],
                }
                # Return data as JSON instead of generating a PDF
                return Response(
                    {
                        "status_code": 200,
                        "status": "success",
                        "message": "Mail data retrieved successfully",
                        "data": response_data
                    },
                    status=status.HTTP_200_OK
                )
            else:
                return Response(
                    {
                        "status_code": 400,
                        "status": "error",
                        "message": f"Transporter Mail is not generated since Incoterm is {transportmail_serializer.data['IncoTerm']}",
                        "data": None
                    },
                    status=status.HTTP_400_BAD_REQUEST
                )
        else:
            return Response(
                {
                    'status_code': status.HTTP_404_NOT_FOUND,
                    'status': "error",
                    'message': "No orders found",
                    'data': None,
                },
                status=status.HTTP_404_NOT_FOUND
            )


class MultipleTransportMailView(APIView):

    def post(self, request, *args, **kwargs):
        """ function to retrieve multiple order details to notify transporter"""
        order_ids = request.data.get('order_ids')

        if not order_ids:
            return Response(
                {
                    "status_code": 400,
                    "status": "error",
                    "message": "The 'order_ids' field is required.",
                    "data": None
                },
                status=status.HTTP_400_BAD_REQUEST
            )

        orders = Orders.objects.filter(OrderNo__in=order_ids, IsDeleted=False).order_by('ExactOrderNo')

        if not orders:
            return Response(
                {
                    "status_code": 400,
                    "status": "error",
                    "message": f"The orders for id {order_ids} not found ",
                    "data": None
                },
                status=status.HTTP_400_BAD_REQUEST
            )
        purchase_utils.validate_orders(orders)

        if orders.exists():
            response_data = purchase_utils.get_content_data_for_transporter(orders[0], request)

            transport_mail_serializer = purchase_serializer.MultipleTransportMailSerializer(
                orders, many=True, context={'request': request})
            order_data = transport_mail_serializer.data
            formated_exact_order_no = ''
            for instance in order_data:
                formated_exact_order_no += f"O/Ref. {instance['ExactOrderNo']}-Y/Ref.{instance['PurchaseOrderNo']} | ,  "
            formated_exact_order_no = formated_exact_order_no[:-5]

            response_data['orders'] = order_data
            subject = response_data['subject']
            subject = f"{subject}- ({formated_exact_order_no})"

            response_data['subject'] = subject

            # Return data as JSON instead of generating a PDF
            return Response(
                {
                    "status_code": 200,
                    "status": "success",
                    "message": "Mail data retrieved successfully",
                    "data": response_data
                },
                status=status.HTTP_200_OK
            )

        else:
            return Response(
                {
                    'status_code': status.HTTP_404_NOT_FOUND,
                    'status': "error",
                    'message': "No orders found",
                    'data': None,
                },
                status=status.HTTP_404_NOT_FOUND
            )


class CustomerMailView(APIView):
    def post(self, request, *args, **kwargs):
        order_id = request.data.get('order_id')
        if not order_id:
            return Response(
                {
                    "status_code": 400,
                    "status": "error",
                    "message": "The 'order_id' field is required.",
                    "data": None
                },
                status=status.HTTP_400_BAD_REQUEST
            )

        order_details = Orders.objects.filter(OrderNo=order_id, IsDeleted=False).first()
        if order_details:
            customermail_serializer = CustomerMailSerializer(order_details, context={'request': request})
            #format data
            product = customermail_serializer.data['Product'].replace("trading", "")
            subject = f"PVS Order Confirmation -{customermail_serializer.data['CustomerName']}-{product}- O/Ref.{customermail_serializer.data['ExactOrderNo']}-Y/Ref.{customermail_serializer.data['PurchaseOrderNo'] if customermail_serializer.data['PurchaseOrderNo'] else 'N/A'}"
            client_address_line2 = f"{customermail_serializer.data['CustomerCountryCode']}-{customermail_serializer.data['CustomerPostalCode']}  {customermail_serializer.data['CustomerCity']}"
            if customermail_serializer.data['Price'] != '0.000':
                price_decimal = Decimal(customermail_serializer.data['Price']).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)# Convert and round off to 2 decimal
                price = f"{convert_to_belgium_format(price_decimal)} EUR/MT"
            else:
                price = "Price to be confirmed"
            if customermail_serializer.data['IncoTerm'] == 'FCA' or customermail_serializer.data['IncoTerm'] == 'EXW':
                delivery_condition = {customermail_serializer.data['IncoTerm']}
            else:
                delivery_condition = f"{customermail_serializer.data['IncoTerm']}  {customermail_serializer.data['CustomerCity']}"
            if customermail_serializer.data['IncoTerm'] == 'FCA' or customermail_serializer.data['IncoTerm'] == 'EXW':
                load_point = customermail_serializer.data['LoadPoint']
            else:
                load_point = ''

            cc_mails = [email.strip() for email in customermail_serializer.data.get('CCMailId', []) if isinstance(email, str) and email.strip()]
            if 'sales@pvs.be' not in cc_mails:
                cc_mails.append('sales@pvs.be')

            response_data = {
                'to': [
                    email for email in customermail_serializer.data['ReceipientMailId']
                    if email and isinstance(email, str) and email.strip()
                ],
                'cc': cc_mails,
                'subject': subject,
                'date': datetime.today().strftime('%d/%m/%Y'),
                'customer_exact_id':customermail_serializer.data['CustomerExactAddressId'],
                'client_name': customermail_serializer.data['CustomerName'],
                'client_address_line1': customermail_serializer.data['CustomerAddress'],
                'client_address_line2':client_address_line2,
                'client_address_line3':customermail_serializer.data['CustomerCountry'],
                'purchase_order_no':customermail_serializer.data['PurchaseOrderNo'],
                'exact_order_no': customermail_serializer.data['ExactOrderNo'],
                'product': customermail_serializer.data['FormattedProductName'],
                'article_code': customermail_serializer.data['ArticleCode'],
                'price': price,
                'quantity':float(customermail_serializer.data['Quantity']),
                'packaging': customermail_serializer.data['Packaging'],
                'packaging_info': purchase_utils.get_PackagingInfo(order_id),
                'delivery_date': (
                    datetime.strptime(customermail_serializer.data['DeliveryDate'], "%Y-%m-%d").strftime("%d/%m/%Y")
                    if customermail_serializer.data['DeliveryDate']
                    else None
                ),
                'delivery_time': customermail_serializer.data['DeliveryTimeInterval'],
                'delivery_condition':delivery_condition,
                'payment_term':customermail_serializer.data['PaymentTerm'],
                # 'is_coc_needed':customermail_serializer.data['IsCocNeeded'],
                'is_coc_needed':1,
                'incoterm':customermail_serializer.data['IncoTerm'],
                'loading_date':datetime.strptime(customermail_serializer.data['LoadingDate'], "%Y-%m-%d").strftime("%d/%m/%Y"),
                'loading_time': customermail_serializer.data['LoadingTime'],
                'customer_id':customermail_serializer.data['OrderedCustomerId'],
                'load_point':load_point,
                'load_point_address_line1':customermail_serializer.data['LoadPointAddressLine1'],
                'load_point_address_line2': customermail_serializer.data['LoadPointAddressLine2'],
                'extra_charge': customermail_serializer.data['ExtraCharges'], 
                'total_extra_charge': customermail_serializer.data['ToTalExtraCharge'], 
                'default_attachments': customermail_serializer.data['DefaultAttachments'], 
            }
            return Response(
                {
                    "status_code": 200,
                    "status": "success",
                    "message": "Mail data retrieved successfully",
                    "data": response_data
                },
                status=status.HTTP_200_OK
            )
        else:
            return Response(
                {
                    'status_code': status.HTTP_404_NOT_FOUND,
                    'status': "error",
                    'message': "No orders found",
                    'data': None,
                },
                status=status.HTTP_404_NOT_FOUND
            )


class CustomerMailMultipleOrderView(APIView):

    def post(self, request, *args, **kwargs):
        """function to get details of multiple orders for notifing order confirmation
            to customers"""
        is_composite_mail = request.data.get('is_composite_mail', False)
        order_ids = request.data.get('order_ids')
        if not order_ids:
            return Response(
                {
                    "status_code": 400,
                    "status": "error",
                    "message": "The 'order_id' field is required.",
                    "data": None
                },
                status=status.HTTP_400_BAD_REQUEST
            )

        order_details = Orders.objects.filter(OrderNo__in=order_ids, IsDeleted=False).order_by('ExactOrderNo')
        if order_details.exists():

            purchase_utils.validate_orders(order_details)

            order_data = purchase_serializer.CustomerMailMultiOrderSerializer(
                order_details, many=True,  context={'request': request}).data
            response_data = purchase_utils.get_content_data_for_customer(order_data, request)

            product = order_data[0]['Product'].replace("trading", "")
            subject = f"PVS Order Confirmation {response_data['client_name']}- {product} "
            attachement_name = ''
            response_data['email_body'] = None

            for order in order_details:
                po_number = OrderRequests.objects.filter(Id=order.OrderNo, IsDeleted=False).values_list(
                    'PurchaseOrderNo', flat=True).first()
                sub_str = f"O/Ref.{order.ExactOrderNo}-Y/Ref.{po_number} | , "
                subject += sub_str
                attachement_name += f"-{order.ExactOrderNo}"
            response_data['subject'] = subject

            if not is_composite_mail:
                order_request_id = order_ids[0]
                emaildraft = po_models.EmailDraft.objects.filter(
                    order_request_id=order_request_id, is_deleted=False, email_type='customer').first()
                if emaildraft:

                    response_data['email_body'] = emaildraft.body
                    response_data['subject'] = emaildraft.subject

            response_data['confirmation_attachement_name'] = f"{response_data['client_name']} {attachement_name}.pdf"

            # Return data as JSON instead of generating a PDF
            response_data['orders'] = order_data
            return Response(
                {
                    "status_code": 200,
                    "status": "success",
                    "message": "Mail data retrieved successfully",
                    "data": response_data
                },
                status=status.HTTP_200_OK
            )
        else:
            return Response(
                {
                    'status_code': status.HTTP_404_NOT_FOUND,
                    'status': "error",
                    'message': "No orders found",
                    'data': None,
                },
                status=status.HTTP_404_NOT_FOUND
            )


class GenerateCMRView(APIView):
    def post(self, request, *args, **kwargs):
        order_id = request.data.get('order_id')
        if not order_id:
            return Response(
                {
                    "status_code": 400,
                    "status": "error",
                    "message": "The 'order_id' field is required.",
                    "data": None
                },
                status=status.HTTP_400_BAD_REQUEST
            )
        order_details = Orders.objects.filter(OrderNo=order_id, IsDeleted=False).first()
        if order_details:

            details = Orders.objects.filter(OrderNo=order_id, IsDeleted=False).values('IncoTerm', 'LoadPoint')
            # if details[0]['LoadPoint'] == 'PVS':
            cmr_serializer = CMRSerializer(order_details, context={'request': request})
            date_object = datetime.strptime(cmr_serializer.data['LoadingDate'], "%Y-%m-%d")
            formatted_loading_date = date_object.strftime("%d/%m/%Y")
            loading_month = date_object.strftime("/%m/%Y")
            if cmr_serializer.data['DeliveryDate']:
                date_object = datetime.strptime(cmr_serializer.data['DeliveryDate'], "%Y-%m-%d")
                formatted_delivery_date = date_object.strftime("%d/%m/%Y")
                delivery_month = date_object.strftime("/%m/%Y")
            else:
                formatted_delivery_date = ''
                delivery_month = ''
            if details[0]['IncoTerm'] == 'FCA':
                company_name = cmr_serializer.data['DeliveryCustomerName']
                company_address = (
                    (cmr_serializer.data.get('DeliveryAddressLine1') or '') + ", " +
                    (cmr_serializer.data.get('DeliveryAddressLine2') or '')
                ).strip(", ")
                company_city = cmr_serializer.data['DeliveryCity']
                company_phone = cmr_serializer.data['DeliveryPhone']
                company_fax = ''
            else:
                company_name = 'PVS CHEMICALS BELGIUM NV'
                company_address = 'Pantserschipstraat 80'
                company_city = 'BE - 9000 GENT'
                company_phone = 'TEL. 09/257.77.00'
                company_fax = 'FAX. 09/257.77.22'
            # if os.environ.get('DJANGO_ENV') == 'staging':
            #     certificates_map = {
            #         'IsWeighingTicketNeeded': 'WEEGTICKET / TICKET DE PASAGE',
            #         'IsCOCNeeded': 'CONFORMITEITSATTEST/ CERTIFICAT DE CONFORMITE',
            #         # 'IsCOANeeded': 'CERTIFICATE OF ANALYSIS',
            #         'IsSealingReportNeeded': 'ZEGELRAPPORT/RAPORT DES PLOMBS',
            #         'IsCleaningCertificateNeeded': 'Cleaning Report'
            #     }
            #     certificates_needed = [
            #         cert_name for key, cert_name in certificates_map.items() if cmr_serializer.data.get(key) == 1
            #     ]
            # else:
            #     keys_to_check = [
            #         'IsWeighingTicketNeeded',
            #         'IsCOCNeeded',
            #         'IsSealingReportNeeded',
            #         'IsCleaningCertificateNeeded'
            #     ]

            #     certificates_needed = [
            #         cmr_serializer.data[key].strip()
            #         for key in keys_to_check
            #         if key in cmr_serializer.data and isinstance(cmr_serializer.data[key], str) and cmr_serializer.data[
            #             key].strip()
            #     ]


            response_data = {
                'company_name': company_name,
                'company_address': company_address,
                'company_city': company_city,
                'company_phone': company_phone,
                'company_fax': company_fax,

                'transporter_name': cmr_serializer.data['TransporterName'],
                'transporter_address_line1': cmr_serializer.data['TransporterAddressLine1'],
                'transporter_address_line2': cmr_serializer.data['TransporterAddressLine2'],
                'transporter_postal_code': cmr_serializer.data['TransporterPostalCode'],
                'transporter_city': cmr_serializer.data['TransporterCity'],
                'transporter_country_code': cmr_serializer.data['TransporterCountryCode'],

                'customer_name': cmr_serializer.data['DeliveryCustomerName'],
                'customer_address_line1': cmr_serializer.data['DeliveryAddressLine1'],
                'customer_address_line2': cmr_serializer.data['DeliveryAddressLine2'],
                'customer_postal_code': cmr_serializer.data['DeliveryPostalCode'],
                'customer_city': cmr_serializer.data['DeliveryCity'],
                'customer_country_code': cmr_serializer.data['DeliveryCountryCode'],

                'loading_country_code':'BE',
                'loading_country':'GENT',
                'loading_month':loading_month,
                'delivery_month':delivery_month,
                'product_code':cmr_serializer.data['ArticleCode'],
                'weight_label': cmr_serializer.data['WeightLabel'],
                'gross_weight': cmr_serializer.data['GrossWeight'],
                'product_name_dutch': (
                                        re.sub(r'trading', '', cmr_serializer.data['DU_ProductName'], flags=re.IGNORECASE)
                                        if cmr_serializer.data['DU_ProductName'] is not None else None
                                      ),
                'product_name_french' : (
                                        re.sub(r'trading', '', cmr_serializer.data['FR_ProductName'], flags=re.IGNORECASE)
                                        if cmr_serializer.data['FR_ProductName'] is not None else None
                                    ),

                'product_name_english' : (
                                        re.sub(r'trading', '', cmr_serializer.data['EN_ProductName'], flags=re.IGNORECASE)
                                        if cmr_serializer.data['EN_ProductName'] is not None else None
                                    ),
                'loading_date':formatted_loading_date,
                'delivery_date':formatted_delivery_date,
                'loading_time':cmr_serializer.data['LoadingTime'],
                'delivery_time':cmr_serializer.data['DeliveryTimeInterval'],
                'exact_order_no':cmr_serializer.data['ExactOrderNo'],
                'purchase_order_no':cmr_serializer.data['ExactOrderNo'] if cmr_serializer.data['IncoTerm'] == 'FCA' else '',
                'load_reference':cmr_serializer.data['LoadReference'],
                'certificates_needed':cmr_serializer.data['cmr_documents'],
                'inco_term':cmr_serializer.data['IncoTerm'],
                'tank_value':cmr_serializer.data['TankType'],
                'custom_text':cmr_serializer.data['CustomText'],
                'client_reference': cmr_serializer.data['PurchaseOrderNo'] if cmr_serializer.data.get('PurchaseOrderNo') else 'N/A',
                'station_reference': cmr_serializer.data['StationReference'],
            }

            # if product is PS 3 batch no is provided
            if cmr_serializer.data['ArticleCode'] == '50000':
                response_data['batch_no'] = cmr_serializer.data['BatchNo']

            return Response(
                {
                    "status_code": 200,
                    "status": "success",
                    "message": "CMR data retrieved successfully",
                    "data": response_data
                },
                status=status.HTTP_200_OK
            )
            # else:
            #     return Response(
            #         {
            #             "status_code": 400,
            #             "status": "error",
            #             "message": "CMR has not been generated as the loading location is not PVS.",
            #             "data": None
            #         },
            #         status=status.HTTP_400_BAD_REQUEST
            #     )
        else:
            return Response(
                {
                    'status_code': status.HTTP_404_NOT_FOUND,
                    'status': 'error',
                    'message': "No orders found",
                    'data': None,
                },
                status=status.HTTP_404_NOT_FOUND
            )


class SendEmailAPIViewOLD(APIView):
    def post(self, request):
        print(f'Api hitted ==================================',  request.headers)
    
        # try:    
        data = request.data
        # Extract data from request
        attachments = data.pop("attachments", [])
        subject = data.get("subject", "No Subject")
        body = data.get("body", "")  # Can be HTML content
        sender_email = os.getenv('EMAIL_HOST_USER')  # Update as needed
        recipient_email = data.get("to", [""])  # List of recipient emails
        cc_email = data.get("cc", [])  # List of CC emails
        # attachments = data.get("attachments", [])  # List of base64 encoded PDFs
        initiated_by = data.get("initiated_by", "")
        order_ids = data.get("order_id", "")
        email_type = data.get("type", "")
        receipient_id = data.get("receipient_id", "")
        customer_exact_id = data.get("customer_exact_id", None)
        esds_form = data.get("esds_form", None)
        default_attachments = data.get("default_attachments", [])

        for id in order_ids:
                payload_log = po_models.PayloadLog.objects.create(
                    order_id=id,
                    request_payload=data,
                    status="pending", 
                    payload_type=email_type
                )
                
        # Validation checks
        if not subject:
            return Response({
                "status_code": 400,
                "status": "error",
                "message": "Subject is required"
            }, status=status.HTTP_400_BAD_REQUEST)
        if not body:
            return Response({
                "status_code": 400,
                "status": "error",
                "message": "Email body is required"
            }, status=status.HTTP_400_BAD_REQUEST)
        if not recipient_email:
            return Response({
                "status_code": 400,
                "status": "error",
                "message": "Recipient email is required"
            }, status=status.HTTP_400_BAD_REQUEST)
        if not recipient_email or not isinstance(recipient_email, list) or not all(recipient_email):
            return Response({
                "status_code": 400,
                "status": "error",
                "message": "Recipient email is required"
            }, status=status.HTTP_400_BAD_REQUEST)
        if not receipient_id:
            return Response({
                "status_code": 400,
                "status": "error",
                "message": "Recipient not selected or not found"
            }, status=status.HTTP_400_BAD_REQUEST)
        if not email_type:
            return Response({
                "status_code": 400,
                "status": "error",
                "message": "type is required"
            }, status=status.HTTP_400_BAD_REQUEST)
        if not initiated_by:
            return Response({
                "status_code": 400,
                "status": "error",
                "message": "initiated_by is required"
            }, status=status.HTTP_400_BAD_REQUEST)
        if not order_ids:
            return Response({
                "status_code": 400,
                "status": "error",
                "message": "order_ids are required"
            }, status=status.HTTP_400_BAD_REQUEST)

        if email_type=="customer" or email_type=="transporter":
            customer_exact_id = request.data.get("customer_exact_id")
            if not customer_exact_id:
                return Response({
                    "status_code": 400,
                    "status": "error",
                    "message": "customer_exact_id is required"
                }, status=status.HTTP_400_BAD_REQUEST)    

        # Create EmailMessage
        if request.is_test_user:
            login_user_email = request.login_user_email
            test_to_mails = [login_user_email]
            test_cc_mails = ["ashik.os@tycaninc.com","ashmi.ma@tycaninc.com", "vishnu@tycaninc.com"]
            email = EmailMessage(subject, body, sender_email, test_to_mails, cc=test_cc_mails)
        else:
            email = EmailMessage(subject, body, sender_email, recipient_email, cc=cc_email)

        email.content_subtype = "html"  # Set content type to HTML
        attachment_names = []
        # Handle attachments (Base64 encoded PDFs)
        for attachment in attachments:
            file_name = attachment.get("name", "document.pdf")
            file_data = attachment.get("data")  # Base64 encoded content
            if file_data:
                decoded_file = base64.b64decode(file_data)
                email.attach(file_name, decoded_file, "application/pdf")
                attachment_names.append(file_name)
        if email_type=='courier' and esds_form:
            file_name = 'eSDS BE-NL Zwavelzuur 96-98% (7664-93-9) v11.pdf'
            file_path = os.path.join(settings.BASE_DIR, 'media', 'pdfs', file_name)
            if os.path.exists(file_path):
                email.attach_file(file_path)
            else:
                print(f"⚠️ File not found: {file_path}")
        
        # Include default attachments that needs to be added to email
        if default_attachments:
            for file_id in default_attachments:
                attachment = po_models.EmailAttachment.objects.get(id=file_id) 
                try:
                    if attachment.file_path:
                        file_path = os.path.join(settings.BASE_DIR, 'media', attachment.file_path.path)
                        email.attach_file(file_path)
                except:
                    return Response({
                    "status_code": 400,
                    "status": "error",
                    "message": "Files Not Found"
                }, status=status.HTTP_400_BAD_REQUEST)

        # Send email and check response
        email_sent_count = email.send()
        purchase_utils.manage_email_drafts(order_ids, email_type)

        # Save email log to database
        for order_id in order_ids:
            # Save email log to database
            EmailLog.objects.create(
                sender=sender_email,
                recipient=", ".join(recipient_email),
                cc=", ".join(cc_email),
                subject=subject,
                body=body,
                sent_at=now(),
                status="success" if email_sent_count > 0 else "failed",
                triggered_by=initiated_by,
                order_id=order_id,
                type=email_type,
                receipient_id=receipient_id,
                attachment=attachment_names, 
                email_response=email_sent_count
            )
            
            history_label = {
            "customer": "Customer Confirmation sent",
            "transporter": "Transporter Confirmation sent", 
            "transporter_cancellation" : "Transporter Cancellation sent",
            "customer_cancellation" : "Customer Cancellation sent",
            "transporter_cancelled": "Transporter cancelled", 
            "customer_replan_sent": "Replan notified to Customer", 
            "transporter_replan_sent": "Replan notified to Transporter", 
            'taken_from_same_batch': 'Email sent to lab',
            'analyzed_by_customer': 'Email sent to lab',  
            'taken_from_truck':  'Email sent to lab', 
            'taken_from_other_customer':  'Email sent to lab', 
            'courier': 'Email sent to courier service provider',
            "lab_cancellation" : "Cancellation mail for lab sent",
            "courrier_cancellation" : "Cancellation mail for courrier sent",
            'lab_replan': 'Replan notified to lab',
            'courier_replan': 'Replan notified to courier',
        }
            
            if email_type in history_label.keys():
                OrderHistory.objects.create(
                        OrderRequestId=order_id,
                        Updation= history_label.get(email_type, None),
                        UpdatedBy=request.login_user_id,
                        UpdatedOn=datetime.now(),
                        IsDeleted=0,
                        history_type=email_type
                    )

        order = Orders.objects.get(OrderNo=order_id)
        product_data = fetch_data.get_product_data(order.ProductId)


        if email_sent_count > 0:
            if email_type=="customer":
                CustomerContacts.objects.filter(
                    ExactERPAddressId=customer_exact_id, product_article=product_data['article_code']).delete()
                for email in recipient_email:
                    CustomerContacts.objects.create(
                        ExactERPAddressId=customer_exact_id,
                        product_article=product_data['article_code'],
                        product_id=order.ProductId,
                        Email=email,
                        Type="to"
                    )
                for email in cc_email:
                    CustomerContacts.objects.create(
                        ExactERPAddressId=customer_exact_id,
                         product_article=product_data['article_code'],
                        product_id=order.ProductId,
                        Email=email,
                        Type="cc"
                    )
            if email_type=="transporter":
                purchase_utils.update_transporter_contact_history(
                    order_id, customer_exact_id, recipient_email, cc_email, receipient_id)

            payload_log.status = email_sent_count
            payload_log.save()
                
            return Response(
                {
                    "status_code": 200,
                    "status": "success",
                    "message": "Email sent successfully",
                },
                status=status.HTTP_200_OK
            )
        else:
            return Response(
                {
                    "status_code": 500,
                    "status": "failed",
                    "message": "Email delivery failed.Please try again",
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
        # except Exception as e:
        #     print(f'Email not sent ==================================={str(e)}')
        #     for order_id in order_ids:
        #         # Log error in database
        #         EmailLog.objects.create(
        #             sender=sender_email,
        #             recipient=", ".join(recipient_email),
        #             cc=", ".join(cc_email),
        #             subject=subject,
        #             body=body,
        #             sent_at=now(),
        #             status="error",
        #             error_message=str(e),
        #             triggered_by=initiated_by,
        #             order_id=order_id,
        #             type=email_type,
        #             receipient_id=receipient_id,
        #             attachment=attachment_names
        #         )
        #     return Response({
        #         "status_code": 500,
        #         "status": "failed",
        #         "message": "An error occurred", "error": str(e),
        #         "data": None
        #     }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        # except Exception as e:
        #     print(f'issue found {str(e)}: printing request body')
        #     print(request.data)
        #     return Response({
        #             "status_code": 500,
        #             "status": "failed",
        #             "message": "An error occurred", "error": str(e),
        #             "data": None
        #         }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)



import json

class SendEmailAPIView(APIView):
    def post(self, request):
        print(f'Api hitted ==================================',  request.headers)

        data = request.POST 
        attachments = request.FILES.getlist('attachments') 
        log_data = request.POST.copy() 
        
        # Parse list fields (JSON sent via FormData usually arrives as strings)
        try:
            order_ids = json.loads(data.get("order_id", "[]"))
            recipient_emails = json.loads(data.get("to", "[]"))
            cc_emails = json.loads(data.get("cc", "[]"))
            default_attachments = json.loads(data.get("default_attachments", "[]"))
            # The transporter availability and price request addresses every
            # carrier privately, so none of them sees who else was asked.
            bcc_emails = json.loads(data.get("bcc", "[]"))
            # [{"transporter_id": 12, "mail_ids": [...]}] - recorded after the
            # send so the screen can show who has been asked.
            request_transporters = json.loads(data.get("transporters", "[]"))
        except json.JSONDecodeError:
            return Response({"message": "Invalid format for list fields"}, status=status.HTTP_400_BAD_REQUEST)

        subject = data.get("subject", "No Subject")
        body = data.get("body", "")
        initiated_by = data.get("initiated_by")
        email_type = data.get("email_type")
        receipient_id = data.get("receipient_id")
        customer_exact_id = data.get("customer_exact_id")
        sender_email = os.getenv('EMAIL_HOST_USER')
        esds_form = data.get("esds_form", None)
    
        for o_id in order_ids:
            po_models.PayloadLog.objects.create(
                order_id=o_id,
                request_payload=log_data,
                status="pending", 
                payload_type=email_type
            )
        

        required_fields = {
            "subject": subject,
            "body": body,
            "recipient_emails": recipient_emails,
            "receipient_id": receipient_id,
            "email_type": email_type,
            "initiated_by": initiated_by,
            "order_ids": order_ids
        }

        # A transporter request is addressed entirely by bcc, so it has no
        # recipients in "to" and must not be judged against that requirement.
        if email_type == "transporter_request":
            required_fields.pop("recipient_emails", None)

        for field, value in required_fields.items():
            if not value:
                return Response({"status": "error", "message": f"{field} is required"}, status=status.HTTP_400_BAD_REQUEST)

        # Enforced here rather than trusted to the caller: one slip exposes the
        # whole carrier list to its competitors and cannot be undone.
        if email_type == "transporter_request":
            if any(address for address in recipient_emails):
                return Response({
                    "status_code": 400,
                    "status": "error",
                    "message": "A transporter request must address carriers via bcc, not to."
                }, status=status.HTTP_400_BAD_REQUEST)
            if cc_emails and any(address in cc_emails for address in bcc_emails):
                return Response({
                    "status_code": 400,
                    "status": "error",
                    "message": "A transporter must not appear in cc on a transporter request."
                }, status=status.HTTP_400_BAD_REQUEST)
            if not bcc_emails:
                return Response({
                    "status_code": 400,
                    "status": "error",
                    "message": "bcc is required for a transporter request"
                }, status=status.HTTP_400_BAD_REQUEST)


        # The ERC warehouse mail must carry the purchase order. It arrives in its
        # own field, not among the general attachments, so it cannot be mistaken
        # for any other upload. Checked here as well as on screen: the screen's
        # check alone could be skipped by any other caller.
        purchase_order = request.FILES.get('purchase_order')
        if email_type == "third_party_warehouse":
            po_order = (Orders.objects.filter(
                OrderNo=order_ids[0], IsDeleted=False).first()
                if order_ids else None)
            if requires_purchase_order(po_order):
                if not purchase_order:
                    return Response({
                        "status_code": 400,
                        "status": "error",
                        "message": PURCHASE_ORDER_REQUIREMENT["message"],
                    }, status=status.HTTP_400_BAD_REQUEST)
                if not purchase_order.name.lower().endswith('.pdf'):
                    return Response({
                        "status_code": 400,
                        "status": "error",
                        "message": "The purchase order must be a PDF file.",
                    }, status=status.HTTP_400_BAD_REQUEST)
        else:
            purchase_order = None

        if email_type=="customer" or email_type=="transporter":
            customer_exact_id = request.data.get("customer_exact_id")
            if not customer_exact_id:
                return Response({
                    "status_code": 400,
                    "status": "error",
                    "message": "customer_exact_id is required"
                }, status=status.HTTP_400_BAD_REQUEST)    

        # Create EmailMessage
        if request.is_test_user:
            login_user_email = request.login_user_email
            test_to_mails = [login_user_email]
            test_cc_mails = ["ashmi.ma@tycaninc.com", "vishnu@tycaninc.com", "ashik.os@tycaninc.com"]
            email = EmailMessage(subject, body, sender_email, test_to_mails, cc=test_cc_mails)
        else:
            email = EmailMessage(subject, body, sender_email, recipient_emails,
                                 cc=cc_emails, bcc=bcc_emails)

        email.content_subtype = "html"  # Set content type to HTML
        attachment_names = []

        # Handle attachments 
        for f in attachments:
            email.attach(f.name, f.read(), f.content_type)
            attachment_names.append(f.name)

        if purchase_order:
            email.attach(purchase_order.name, purchase_order.read(),
                         'application/pdf')
            attachment_names.append(purchase_order.name)

        if email_type=='courier' and esds_form:
            file_name = 'eSDS BE-NL Zwavelzuur 96-98% (7664-93-9) v11.pdf'
            file_path = os.path.join(settings.BASE_DIR, 'media', 'pdfs', file_name)
            if os.path.exists(file_path):
                email.attach_file(file_path)
            else:
                print(f"⚠️ File not found: {file_path}")
        
        # Include default attachments that needs to be added to email
        if default_attachments:
            for file_id in default_attachments:
                attachment = po_models.EmailAttachment.objects.get(id=file_id) 
                try:
                    if attachment.file_path:
                        file_path = os.path.join(settings.BASE_DIR, 'media', attachment.file_path.path)
                        email.attach_file(file_path)
                except:
                    return Response({
                    "status_code": 400,
                    "status": "error",
                    "message": "Files Not Found"
                }, status=status.HTTP_400_BAD_REQUEST)

        # Send email and check response
        email_sent_count = email.send()
        purchase_utils.manage_email_drafts(order_ids, email_type)

        # Which carriers were asked, and on what addresses. Written only when the
        # mail actually went out - marking a carrier as asked after a failed send
        # would quietly drop them from the next round.
        if email_type == "transporter_request" and email_sent_count > 0:
            sent_at = now()
            for o_id in order_ids:
                for entry in request_transporters:
                    transporter_id = entry.get("transporter_id")
                    if not transporter_id:
                        continue
                    po_models.OrderTransporterRequests.objects.update_or_create(
                        order_request_id=o_id,
                        transporter_id=transporter_id,
                        defaults={
                            # snapshot: TransporterContacts changes over time
                            "mail_ids_used": ", ".join(entry.get("mail_ids", [])),
                            "request_sent_at": sent_at,
                            "updated_by": initiated_by,
                            "is_deleted": False,
                        },
                    )

        # Save email log to database
        for order_id in order_ids:
            # Save email log to database
            EmailLog.objects.create(
                sender=sender_email,
                recipient=", ".join(recipient_emails),
                cc=", ".join(cc_emails),
                bcc=", ".join(bcc_emails),
                subject=subject,
                body=body,
                sent_at=now(),
                status="success" if email_sent_count > 0 else "failed",
                triggered_by=initiated_by,
                order_id=order_id,
                type=email_type,
                receipient_id=receipient_id,
                attachment=attachment_names, 
                email_response=email_sent_count
            )
            
            history_label = {
            "customer": "Customer Confirmation sent",
            "transporter": "Transporter Confirmation sent", 
            "transporter_cancellation" : "Transporter Cancellation sent",
            "customer_cancellation" : "Customer Cancellation sent",
            "transporter_cancelled": "Transporter cancelled", 
            "customer_replan_sent": "Replan notified to Customer", 
            "transporter_replan_sent": "Replan notified to Transporter", 
            'taken_from_same_batch': 'Email sent to lab',
            'analyzed_by_customer': 'Email sent to lab',  
            'taken_from_truck':  'Email sent to lab', 
            'taken_from_other_customer':  'Email sent to lab', 
            'courier': 'Email sent to courier service provider',
            "lab_cancellation" : "Cancellation mail for lab sent",
            "courrier_cancellation" : "Cancellation mail for courrier sent",
            'lab_replan': 'Replan notified to lab',
            'courier_replan': 'Replan notified to courier',
        }
            
            if email_type in history_label.keys():
                OrderHistory.objects.create(
                        OrderRequestId=order_id,
                        Updation= history_label.get(email_type, None),
                        UpdatedBy=request.login_user_id,
                        UpdatedOn=datetime.now(),
                        IsDeleted=0,
                        history_type=email_type
                    )
        order = Orders.objects.get(OrderNo=order_id)
        product_data = fetch_data.get_product_data(order.ProductId)
        bill_to_address_data = fetch_data.get_address_data(order.BillToCustomerId)
        bill_to_code = bill_to_address_data.get('exact_erp_address_id')

        if email_sent_count > 0:
            if email_type=="customer":
                CustomerContacts.objects.filter(
                    ExactERPAddressId=customer_exact_id, BillTo=bill_to_code, product_article=product_data['article_code']).delete()
                for email in recipient_emails:
                    CustomerContacts.objects.create(
                        ExactERPAddressId=customer_exact_id,
                        BillTo=bill_to_code,
                        product_article=product_data['article_code'],
                        product_id=order.ProductId,
                        Email=email,
                        Type="to"
                    )
                for email in cc_emails:
                    CustomerContacts.objects.create(
                        ExactERPAddressId=customer_exact_id,
                        BillTo=bill_to_code,
                        product_article=product_data['article_code'],
                        product_id=order.ProductId,
                        Email=email,
                        Type="cc"
                    )
            if email_type=="transporter":
                purchase_utils.update_transporter_contact_history(
                    order_id, customer_exact_id, recipient_emails, cc_emails, receipient_id)
                
            return Response(
                {
                    "status_code": 200,
                    "status": "success",
                    "message": "Email sent successfully",
                },
                status=status.HTTP_200_OK
            )
        else:
            return Response(
                {
                    "status_code": 500,
                    "status": "failed",
                    "message": "Email delivery failed.Please try again",
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
        # except Exception as e:
        #     print(f'Email not sent ==================================={str(e)}')
        #     for order_id in order_ids:
        #         # Log error in database
        #         EmailLog.objects.create(
        #             sender=sender_email,
        #             recipient=", ".join(recipient_email),
        #             cc=", ".join(cc_email),
        #             subject=subject,
        #             body=body,
        #             sent_at=now(),
        #             status="error",
        #             error_message=str(e),
        #             triggered_by=initiated_by,
        #             order_id=order_id,
        #             type=email_type,
        #             receipient_id=receipient_id,
        #             attachment=attachment_names
        #         )
        #     return Response({
        #         "status_code": 500,
        #         "status": "failed",
        #         "message": "An error occurred", "error": str(e),
        #         "data": None
        #     }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        # except Exception as e:
        #     print(f'issue found {str(e)}: printing request body')
        #     print(request.data)
        #     return Response({
        #             "status_code": 500,
        #             "status": "failed",
        #             "message": "An error occurred", "error": str(e),
        #             "data": None
        #         }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class ProductPriceFromQuantity(APIView):
    def post(self, request, *args, **kwargs):
        quantity = request.data.get('quantity')
        product_id = request.data.get('product_id')
        inco_term_id = request.data.get('inco_term_id')
        deliver_to_id = request.data.get('deliver_to_id')
        loading_date = request.data.get('loading_date')
        delivery_date = request.data.get('delivery_date' , None)
        special_incoterms = [2, 5]

        # No loading date: Odoo has nothing to price against, so fall back to
        # whatever price a planner has already applied to this order. A packed
        # order can sit in this state from creation until it is planned, and a
        # 400 on every product or quantity change would make the screen look
        # broken. No validity or minimum quantity test is applied - the price
        # was chosen for this order by a person, and there is no better price to
        # fall back to. Once a loading date is set the normal path takes over,
        # re-checks validity and re-asks Odoo.
        if not loading_date:
            applied = None
            order_request_id = request.data.get('order_request_id')
            if order_request_id:
                price_link = purchase_utils.get_order_price_link_id(
                    order_request_id)
                if price_link:
                    applied = purchase_utils.get_applied_price(price_link)

            return Response({
                "status": "success",
                "status_code": status.HTTP_200_OK,
                "message": (
                    "Applied price returned; the order has no loading date yet."
                    if applied else
                    "No price yet: the order has no loading date and no applied "
                    "price."
                ),
                "data": {
                    "Price": applied.get('actual_price') if applied else "",
                    "Quarter": applied.get('QuarterName') if applied else "",
                    "PaymentTerm": applied.get('PaymentTerm') if applied else "",
                    "QtyMsg": "",
                }
            }, status=status.HTTP_200_OK)

        product_data = fetch_data.get_product_data(product_id)
        article_code = product_data['article_code']
        packaging = product_data['packaging']

        if inco_term_id in special_incoterms or article_code == '50000':
            price_filter_date = loading_date
        else:
            price_filter_date = delivery_date if delivery_date else loading_date



        if quantity and product_id and inco_term_id and deliver_to_id and loading_date:
            # product_article_code = get_product_articlecode(request.headers.get('x-auth-token'), product_id)
            # deliver_to_address_code = get_address_code_from_id(request.headers.get('x-auth-token'), deliver_to_id)
            # formatted_quantity = Decimal(str(quantity)).quantize(Decimal('0.00'))

            # base_queryset = PriceMaster.objects.filter(
            #     ArticleCode=product_article_code,
            #     IncotermID=inco_term_id,
            #     ExactERPAddressId=deliver_to_address_code,
            #     IsConfirmed=1,
            #     IsDeleted=0,
            #     ValidityStartDate__lte=price_filter_date,
            #     ValidityEndDate__gte=price_filter_date
            #     )

            # price_master = purchase_utils.get_best_price(base_queryset, formatted_quantity)

            # price_data = {}
            # if price_master:
            #     price_data['Price'] = price_master.Price
            #     price_data['Quarter'] = price_master.QuarterName
            #     price_data['PaymentTerm'] = price_master.PaymentTerm
            #     price_data['QtyMsg'] = ""
            # else:
            #     price_master = PriceMaster.objects.filter(  # check without minimum quantity conditions
            #         ArticleCode=product_article_code,
            #         IncotermID=inco_term_id,
            #         ExactERPAddressId=deliver_to_address_code,
            #         IsConfirmed=1,
            #         IsDeleted=0,
            #     ).filter(
            #         Q(MinQuantity__isnull=True)
            #     ).filter(
            #         Q(ValidityStartDate__lte=price_filter_date) & Q(
            #             ValidityEndDate__gte=price_filter_date)  # Date range
            #     ).order_by('-Id').first()
            #     if price_master:
            #         price_data['Price'] = price_master.Price
            #         price_data['Quarter'] = price_master.QuarterName
            #         price_data['PaymentTerm'] = price_master.PaymentTerm
            #         price_data['QtyMsg'] = ""
            #     else:
            #         price_master = PriceMaster.objects.filter(  # check without minimum quantity conditions
            #             ArticleCode=product_article_code,
            #             IncotermID=inco_term_id,
                       
            #             ExactERPAddressId=deliver_to_address_code,
            #             IsConfirmed=1,
            #             IsDeleted=0,
            #         ).filter(
            #             Q(MinQuantity__isnull=False)
            #         ).filter(
            #             Q(ValidityStartDate__lte=price_filter_date) & Q(
            #                 ValidityEndDate__gte=price_filter_date)
            #         ).order_by('MinQuantity','-Id').last()
            #         if price_master:
            #             price_data['Price'] = price_master.Price
            #             price_data['Quarter'] = price_master.QuarterName
            #             price_data['PaymentTerm'] = price_master.PaymentTerm
            #             price_data['QtyMsg'] = f"Pricing is based on a minimum purchase of {convert_to_belgium_format(price_master.MinQuantity)} TO"
            #         else:
            #             price_data['Price'] = 0
            #             price_data['Quarter'] = ""
            #             price_data['PaymentTerm'] = ""
            #             price_data['QtyMsg'] = ""

            deliver_to_data = fetch_data.get_address_data(deliver_to_id)
            incoterm = fetch_data.get_incoterm_data_from_id(inco_term_id)


            payload = {
                'ship_to_code': deliver_to_data['exact_erp_address_id'], 
                'loading_date': datetime.strptime(loading_date, "%Y-%m-%d").strftime("%d-%m-%Y"),
                'article_code': article_code, 
                'qty': quantity,
                'incoterm': incoterm['code']
            }

            client = OdooAPIService()
            try:
                result = client.get_price_from_quantity(params=payload)
                price_data = result.get('data', None)[0]
                is_price_available = price_data['warning']
                response_data = {
                            "Price": price_data['Price'],
                            "Quarter": price_data['QuarterName'],
                            "PaymentTerm": '',
                            "QtyMsg": price_data['message'] if is_price_available else ''
                            }
            except:
                return Response({
                "status_code": 400,
                "status": "error",
                "data": {
                    "Price": 0,
                    "Quarter": "",
                    "PaymentTerm": "",
                    "QtyMsg": "Price Not Found"
                },
                "message": "Price not found"
            }, status=status.HTTP_400_BAD_REQUEST)

            print(response_data)

            response_data = {
                "status": "success",
                "status_code": status.HTTP_200_OK,
                "message": "Price details fetched successfully",
                "data": response_data
            }
            return Response(response_data, status=status.HTTP_200_OK)
        else:
            return Response({
                "status_code": 400,
                "status": "error",
                "message": "quantity ,product_id,inco_term_id,deliver_to_id and loading_date are required"
            }, status=status.HTTP_400_BAD_REQUEST)


class replanOrderDueToStationUpdate(APIView):
    def post(self, request, *args, **kwargs):
        order_id = request.data.get('order_id')
        load_point_id = request.data.get('load_point_id')
        loading_station_id = request.data.get('loading_station_id')
        product_id = request.data.get('product_id')
        deliver_to_id = request.data.get('deliver_to_id')
        incoterm_id = request.data.get('incoterm_id')
        delivery_date = request.data.get('delivery_date')
        loading_date = request.data.get('loading_date')
        quantity = request.data.get('quantity')
        prev_load_point_id = request.data.get('prev_load_point_id')
        product_name = request.data.get('product_name')
        if order_id and load_point_id and loading_station_id and product_id and deliver_to_id and incoterm_id and delivery_date and quantity and loading_date and prev_load_point_id and product_name:
            if load_point_id != 1 and prev_load_point_id != 1: #Loading is changing from one non pvs station to another non pvs station then no need to change the product since it's already trading version
                alternate_product_details = {}
                alternate_product_details['alternate_product_id'] = product_id
                alternate_product_details['alternate_product_name'] = product_name
                alternate_product_details['alternate_article_code'] = get_product_articlecode(request.headers.get('x-auth-token'),product_id)
            else: # loading is changing from pvs to non pvs station or vvice versa,so need to find trading/non-trading version of the product
                alternate_product_details = get_alternate_product(request.headers.get('x-auth-token'), product_id)
            replanned_data = {}
            if alternate_product_details:
                replanned_data['ProductId'] = alternate_product_details['alternate_product_id']
                replanned_data['ProductName'] = alternate_product_details['alternate_product_name']
                replanned_data['ProductArticleCode'] = alternate_product_details['alternate_article_code']
                # transporter
                transporters = get_available_transporters(request.headers.get('x-auth-token'),
                                                          alternate_product_details['alternate_product_id'],
                                                          load_point_id, deliver_to_id, 'Bulk', incoterm_id)
                # Check if transporters data exists and get the first row
                if transporters:
                    replanned_data['TransporterId'] = transporters[0].get('TransporterId')
                    replanned_data['TransporterName'] = transporters[0].get('Transporter')
                else:
                    replanned_data['TransporterId'] = ""
                    replanned_data['TransporterName'] = ""
                # Loading date and time

                loading_datetime_data = get_loading_datetime(request.headers.get('x-auth-token'),
                                                             load_point_id, deliver_to_id)
                if loading_datetime_data:
                    if loading_datetime_data['DateOffset'] is not None:
                        delivery_date = datetime.strptime(delivery_date, "%Y-%m-%d")
                        loading_date = delivery_date - timedelta(days=loading_datetime_data['DateOffset'])
                        if loading_date.date() < date.today():
                            replanned_data['LoadingDate'] = delivery_date
                        else:
                            replanned_data['LoadingDate'] = loading_date.strftime("%Y-%m-%d")
                    else:
                        replanned_data['LoadingDate'] = delivery_date.strftime("%Y-%m-%d")
                    replanned_data['LoadingTime'] = ""
                else:
                    replanned_data['LoadingDate'] = delivery_date
                    replanned_data['LoadingTime'] = ""

                # checking the planned loading date is a holiday,if yes then shift to previous non holiday date
                replanned_data['LoadingDate'] = get_previous_non_holiday(replanned_data['LoadingDate'])

                # cost center details
                cost_center_details = get_costcenter_details(request.headers.get('x-auth-token'),
                                                             alternate_product_details['alternate_product_id'])
                if cost_center_details:
                    replanned_data['CostCenter'] = cost_center_details['costcenter']
                    replanned_data['CostCenterId'] = cost_center_details['costcenter_id']
                else:
                    replanned_data['CostCenter'] = ""
                    replanned_data['CostCenterId'] = ""
                # price calculation starts
                if replanned_data['LoadingDate'] != '':
                    deliver_to_address_code = get_address_code_from_id(request.headers.get('x-auth-token'),
                                                                       deliver_to_id)
                    formatted_quantity = Decimal(str(quantity)).quantize(Decimal('0.00'))
                    price_master = PriceMaster.objects.filter(
                        ArticleCode=alternate_product_details['alternate_article_code'],
                        IncotermID=incoterm_id,
                        Packaging='Bulk',
                        ExactERPAddressId=deliver_to_address_code,
                        IsConfirmed=1,
                        IsDeleted=0,
                        MinQuantity__lte=formatted_quantity,  # Less than or equal to Min Quantity
                    ).filter(
                        Q(ValidityStartDate__lte=replanned_data['LoadingDate']) & Q(
                            ValidityEndDate__gte=replanned_data['LoadingDate'])  # Date range
                    ).order_by(
                        '-MinQuantity','-Id').first()  # Order by MinQuantity in descending order and get the first row ie pick row row with highest quantity in case of mutiple rows

                    if price_master:
                        replanned_data['Price'] = float(price_master.Price)
                        replanned_data['Quarter'] = price_master.QuarterName
                        replanned_data['QtyMsg'] = ""
                    else:
                        price_master = PriceMaster.objects.filter(  # check without minimum quantity conditions
                            ArticleCode=alternate_product_details['alternate_article_code'],
                            IncotermID=incoterm_id,
                            Packaging='Bulk',
                            ExactERPAddressId=deliver_to_address_code,
                            IsConfirmed=1,
                            IsDeleted=0,
                        ).filter(
                            Q(MinQuantity__isnull=True)
                        ).filter(
                            Q(ValidityStartDate__lte=replanned_data['LoadingDate']) & Q(
                                ValidityEndDate__gte=replanned_data['LoadingDate'])  # Date range
                        ).order_by('-Id').first()
                        if price_master:
                            replanned_data['Price'] = float(price_master.Price)
                            replanned_data['Quarter'] = price_master.QuarterName
                            replanned_data['QtyMsg'] = ""
                        else:
                            price_master = PriceMaster.objects.filter(  # check without minimum quantity conditions
                                ArticleCode=alternate_product_details['alternate_article_code'],
                                IncotermID=incoterm_id,
                                Packaging='Bulk',
                                ExactERPAddressId=deliver_to_address_code,
                                IsConfirmed=1,
                                IsDeleted=0,
                            ).filter(
                                Q(MinQuantity__isnull=False)
                            ).filter(
                                Q(ValidityStartDate__lte=replanned_data['LoadingDate']) & Q(
                                    ValidityEndDate__gte=replanned_data['LoadingDate'])  # Date range
                            ).order_by('MinQuantity','-Id').first()
                            if price_master:
                                replanned_data['Price'] = float(price_master.Price)
                                replanned_data['Quarter'] = price_master.QuarterName
                                replanned_data['QtyMsg'] = f"Pricing is based on a minimum purchase of {convert_to_belgium_format(price_master.MinQuantity)} TO"
                            else:
                                replanned_data['Price'] = 0
                                replanned_data['Quarter'] = ""
                                replanned_data['QtyMsg'] = ""

                    if replanned_data['Price'] != 0:
                        replanned_data['TotalPrice'] = float(price_master.Price) * float(quantity)
                    else:
                        replanned_data['TotalPrice'] = 0
                    replanned_data['TotalExtraCharge'] = 0
                    replanned_data['ExtraCharges'] = []

                    replanned_data['PaymentTerm'] =  Orders.objects.filter(OrderNo=order_id,IsDeleted=False).values_list('PaymentTerm', flat=True).first()
                    if loading_date != '' and delivery_date != '':
                        if isinstance(delivery_date, str):
                            date_obj1 = datetime.strptime(delivery_date, '%Y-%m-%d')
                        else:
                            date_obj1 = delivery_date
                        day_index1 = date_obj1.weekday()
                        delivery_day = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'][
                            day_index1]
                        if isinstance(delivery_date, str):
                            date_obj2 = datetime.strptime(loading_date, '%Y-%m-%d')
                        else:
                            date_obj2 = loading_date
                        day_index2 = date_obj2.weekday()
                        loading_day = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'][
                            day_index2]
                        if delivery_day == 'Saturday' and loading_day == 'Friday':
                            additional_charge = {"charge_name": "Saturday Extra Charge", "charge_amount": 575}
                            replanned_data['ExtraCharges'].append(additional_charge)
                            replanned_data['TotalExtraCharge'] += 575
                        elif delivery_day == 'Saturday' and loading_day == 'Saturday':
                            additional_charge = {"charge_name": "Saturday Extra Charge", "charge_amount": 955}
                            replanned_data['ExtraCharges'].append(additional_charge)
                            replanned_data['TotalExtraCharge'] += 955
                        elif delivery_day == 'Sunday' and loading_day == 'Friday':
                            additional_charge = {"charge_name": "Sunday Extra Charge", "charge_amount": 580}
                            replanned_data['ExtraCharges'].append(additional_charge)
                            replanned_data['TotalExtraCharge'] += 580
                        elif delivery_day == 'Sunday' and loading_day == 'Saturday':
                            additional_charge = {"charge_name": "Sunday Extra Charge", "charge_amount": 955}
                            replanned_data['ExtraCharges'].append(additional_charge)
                            replanned_data['TotalExtraCharge'] += 955
                        elif delivery_day == 'Sunday' and loading_day == 'Sunday':
                            additional_charge = {"charge_name": "Sunday Extra Charge", "charge_amount": 1070}
                            replanned_data['ExtraCharges'].append(additional_charge)
                            replanned_data['TotalExtraCharge'] += 1070
                    replanned_data['Price'] = float(replanned_data['Price'])
                    replanned_data['TotalExtraCharge'] = convert_to_belgium_format(replanned_data['TotalExtraCharge'])
                    # price calculation ends

                response_data = {
                    "status": "success",
                    "status_code": status.HTTP_200_OK,
                    "message": "Order replan data fetched successfully",
                    "data": replanned_data
                }
                return Response(response_data, status=status.HTTP_200_OK)
            else:
                return Response({
                    "status_code": 404,
                    "status": "error",
                    "message": "Sorry, No alternative Product found,Kindly Confirm Details Manually"
                }, status=status.HTTP_404_NOT_FOUND)
        else:
            return Response({
                "status_code": 400,
                "status": "error",
                "message": "order_id ,load_point_id,loading_station_id and product_id and deliver_to_id and incoterm_id,delivery_date,quantity,loading_date,prev_load_point_id and product_name are required"
            }, status=status.HTTP_400_BAD_REQUEST)


class EmailHistoryAPIView(APIView):
    def post(self, request, *args, **kwargs):
        order_id = request.data.get('order_id')
        if order_id:
            history = EmailLog.objects.filter(order_id=order_id, status='success').values('type', 'receipient_id')

            if history:
                response_data = {
                    "status": "success",
                    "status_code": status.HTTP_200_OK,
                    "message": "Mail history fetched successfully",
                    "data": history
                }
            else:
                return Response({
                    "status_code": 200,
                    "status": status.HTTP_200_OK,
                    "message": "No mail history found",
                    "data":[]
                }, status=status.HTTP_200_OK)
            return Response(response_data, status=status.HTTP_200_OK)
        else:
            return Response({
                "status_code": 400,
                "status": "error",
                "message": "order_id is required"
            }, status=status.HTTP_400_BAD_REQUEST)


# class ExtraChargeListView(APIView):
#     def post(self, request):
#         required_fields = [
#             "order_request_id", "loading_date", "delivery_date", "quantity"
#         ]
#         data = request.data
#         # Iterate through each field and check if it's null or empty
#         for field in required_fields:
#             value = data.get(field)
#             # If any required field is missing or empty
#             if value is None or (isinstance(value, str) and value.strip() == ''):
#                 # Return error response and stop the process
#                 return Response({
#                     "status_code": 400,
#                     "status": "error",
#                     "message": f"The field '{field}' is required and cannot be null or empty."
#                 }, status=status.HTTP_400_BAD_REQUEST)
#         order_request_id = request.data.get('order_request_id')
#         delivery_date = request.data.get('delivery_date')
#         loading_date = request.data.get('loading_date')
#         quantity = request.data.get('quantity')
#         order_charges = list(OrderCharges.objects.filter(OrderNo=order_request_id, IsDeleted=False)
#                              .exclude(
#             ChargeName__in=["Delivery on Saturday - Loading on Friday", "Delivery on Saturday - Loading on Saturday",
#                             "Delivery on Sunday /bank holiday - Loading on Friday",
#                             "Delivery on Sunday/bank holiday - Loading on Saturday",
#                             "Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday"]
#         ).annotate(
#             IsApplied=Value(True)
#         ).values('ChargeName', 'Rate', 'IsApplied'))
#         if order_charges:
#             extra_charges = ExtraCharges.objects.filter(IsDeleted=False)
#             serializer = ExtraChargeSerializer(extra_charges, many=True)
#             if serializer.data:
#                 existing_charge_names = {charge['ChargeName'] for charge in order_charges}
#                 quantity_surcharge_exists = 0
#                 for extra_charge in serializer.data:
#                     # Check if an existing charge has a name similar to "surcharge for deliveries"
#                     similar_charge_exists = OrderCharges.objects.filter(
#                         OrderNo=order_request_id,
#                         IsDeleted=False,
#                         ChargeName__icontains="specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%"
#                     ).exists()
#                     if similar_charge_exists:
#                         quantity_surcharge_exists = 1
#                         OrderCharges.objects.filter(
#                             OrderNo=order_request_id,
#                             IsDeleted=False,
#                             ChargeName__icontains="specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%"
#                         ).update(IsDeleted=True)
#                         order_charges = list(OrderCharges.objects.filter(OrderNo=order_request_id, IsDeleted=False)
#                                              .exclude(
#                             ChargeName__in=["Delivery on Saturday - Loading on Friday",
#                                             "Delivery on Saturday - Loading on Saturday",
#                                             "Delivery on Sunday /bank holiday - Loading on Friday",
#                                             "Delivery on Sunday/bank holiday - Loading on Saturday",
#                                             "Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday"]
#                         ).annotate(
#                             IsApplied=Value(True)
#                         ).values('ChargeName', 'Rate', 'IsApplied'))
#                     if extra_charge['Name'] not in existing_charge_names:
#                         order_charges.append({
#                             'ChargeName': extra_charge['Name'],
#                             'Rate': extra_charge['Amount'],
#                             'IsApplied': False
#                         })
#
#         else:
#             order_charges = list(
#                 ExtraCharges.objects.filter(IsDeleted=False)
#                 .annotate(
#                     ChargeName=F('Name'),  # Map 'ChargeName' to 'Name'
#                     Rate=F('Amount'),  # Map 'Rate' to 'Amount'
#                     IsApplied=Value(False)  # Add constant field 'IsApplied' with value True
#                 )
#                 .values('ChargeName', 'Rate', 'IsApplied')  # Retrieve the specific fields
#             )
#             quantity_surcharge_exists = 0
#         # Check if rows with the given charge names exist
#         order_charges_to_delete = OrderCharges.objects.filter(
#             OrderNo=order_request_id,
#             IsDeleted=False,
#             ChargeName__icontains="Delivery on Saturday - Loading on Friday"
#         ) | OrderCharges.objects.filter(
#             OrderNo=order_request_id,
#             IsDeleted=False,
#             ChargeName__icontains="Delivery on Saturday - Loading on Saturday"
#         ) | OrderCharges.objects.filter(
#             OrderNo=order_request_id,
#             IsDeleted=False,
#             ChargeName__icontains="Delivery on Sunday /bank holiday - Loading on Friday"
#         ) | OrderCharges.objects.filter(
#             OrderNo=order_request_id,
#             IsDeleted=False,
#             ChargeName__icontains="Delivery on Sunday/bank holiday - Loading on Saturday"
#         ) | OrderCharges.objects.filter(
#             OrderNo=order_request_id,
#             IsDeleted=False,
#             ChargeName__icontains="Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday"
#         )
#         # If such rows exist, update their IsDeleted status to True
#         if order_charges_to_delete.exists():
#             order_charges_to_delete.update(IsDeleted=True)
#         date_obj1 = datetime.strptime(delivery_date, '%Y-%m-%d')
#         day_index1 = date_obj1.weekday()
#         delivery_day = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'][day_index1]
#         date_obj2 = datetime.strptime(loading_date, '%Y-%m-%d')
#         day_index2 = date_obj2.weekday()
#         loading_day = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'][day_index2]
#         if delivery_day == 'Saturday' and loading_day == 'Friday':
#             order_charges.append({
#                 'ChargeName': "Delivery on Saturday - Loading on Friday",
#                 'Rate': "575",
#                 'IsApplied': True
#             })
#             OrderCharges.objects.create(
#                 OrderNo=order_request_id,
#                 ChargeName="Delivery on Saturday - Loading on Friday",
#                 Rate=575,
#             )
#         elif delivery_day == 'Saturday' and loading_day == 'Saturday':
#             order_charges.append({
#                 'ChargeName': "Delivery on Saturday - Loading on Saturday",
#                 'Rate': "955",
#                 'IsApplied': True
#             })
#             OrderCharges.objects.create(
#                 OrderNo=order_request_id,
#                 ChargeName="Delivery on Saturday - Loading on Saturday",
#                 Rate=955,
#             )
#         elif delivery_day == 'Sunday' and loading_day == 'Friday':
#             order_charges.append({
#                 'ChargeName': "Delivery on Sunday /bank holiday - Loading on Friday",
#                 'Rate': "580",
#                 'IsApplied': True
#             })
#             OrderCharges.objects.create(
#                 OrderNo=order_request_id,
#                 ChargeName="Delivery on Sunday /bank holiday - Loading on Friday",
#                 Rate=580,
#             )
#         elif delivery_day == 'Sunday' and loading_day == 'Saturday':
#             order_charges.append({
#                 'ChargeName': "Delivery on Sunday/bank holiday - Loading on Saturday",
#                 'Rate': "955",
#                 'IsApplied': True
#             })
#             OrderCharges.objects.create(
#                 OrderNo=order_request_id,
#                 ChargeName="Delivery on Sunday/bank holiday - Loading on Saturday",
#                 Rate=955,
#             )
#         elif delivery_day == 'Sunday' and loading_day == 'Sunday':
#             order_charges.append({
#                 'ChargeName': "Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday",
#                 'Rate': "1070",
#                 'IsApplied': True
#             })
#             OrderCharges.objects.create(
#                 OrderNo=order_request_id,
#                 ChargeName="Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday",
#                 Rate=1070,
#             )
#         else:  # check delivery day a bank holiday
#             if OffDays.objects.filter(Date=delivery_date, IsDeleted=False).exists():
#                 if loading_day == 'Friday':
#                     order_charges.append({
#                         'ChargeName': "Holiday Extra Charge",
#                         'Rate': "580",
#                         'IsApplied': True
#                     })
#                     OrderCharges.objects.create(
#                         OrderNo=order_request_id,
#                         ChargeName="Holiday Extra Charge",
#                         Rate=580,
#                     )
#                 elif loading_day == 'Saturday':
#                     order_charges.append({
#                         'ChargeName': "Holiday Extra Charge",
#                         'Rate': "955",
#                         'IsApplied': True
#                     })
#                     OrderCharges.objects.create(
#                         OrderNo=order_request_id,
#                         ChargeName="Holiday Extra Charge",
#                         Rate=955,
#                     )
#                 elif loading_day == 'Sunday':
#                     order_charges.append({
#                         'ChargeName': "Holiday Extra Charge",
#                         'Rate': "1070",
#                         'IsApplied': True
#                     })
#                     OrderCharges.objects.create(
#                         OrderNo=order_request_id,
#                         ChargeName="Holiday Extra Charge",
#                         Rate=1070,
#                     )
#                 elif OffDays.objects.filter(Date=loading_date, IsDeleted=False).exists():
#                     order_charges.append({
#                         'ChargeName': "Holiday Extra Charge",
#                         'Rate': "1070",
#                         'IsApplied': True
#                     })
#                     OrderCharges.objects.create(
#                         OrderNo=order_request_id,
#                         ChargeName="Holiday Extra Charge",
#                         Rate=1070,
#                     )
#
#         if quantity < 25:
#             if quantity_surcharge_exists == 1:
#                 IsApplied = True
#             else:
#                 IsApplied = False
#             if 20 <= quantity < 25:
#                 order_charges.append({
#                     'ChargeName': '€13/MT surcharge for deliveries of 20-25MT, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)',
#                     'Rate': quantity * 13,
#                     'IsApplied': IsApplied
#                 })
#                 if IsApplied == True:
#                     OrderCharges.objects.create(
#                         OrderNo=order_request_id,
#                         ChargeName="€13/MT surcharge for deliveries of 20-25MT, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)",
#                         Rate=quantity * 13,
#                     )
#             elif 15 <= quantity < 20:
#                 order_charges.append({
#                     'ChargeName': '€30/MT surcharge for deliveries of 15-20MT, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)',
#                     'Rate': quantity * 30,
#                     'IsApplied': IsApplied
#                 })
#                 if IsApplied == True:
#                     OrderCharges.objects.create(
#                         OrderNo=order_request_id,
#                         ChargeName="€30/MT surcharge for deliveries of 15-20MT, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)",
#                         Rate=quantity * 30,
#                     )
#             elif 10 <= quantity < 15:
#                 order_charges.append({
#                     'ChargeName': '€55/MT surcharge for deliveries of 10-15MT, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)',
#                     'Rate': quantity * 55,
#                     'IsApplied': IsApplied
#                 })
#                 if IsApplied == True:
#                     OrderCharges.objects.create(
#                         OrderNo=order_request_id,
#                         ChargeName="€55/MT surcharge for deliveries of 10-15MT, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)",
#                         Rate=quantity * 55,
#                     )
#             elif quantity <= 5:
#                 order_charges.append({
#                     'ChargeName': '€283/MT surcharge for deliveries of 5MT or less, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)',
#                     'Rate': quantity * 283,
#                     'IsApplied': IsApplied
#                 })
#                 if IsApplied == True:
#                     OrderCharges.objects.create(
#                         OrderNo=order_request_id,
#                         ChargeName="€283/MT surcharge for deliveries of 5MT or less, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)",
#                         Rate=quantity * 283,
#                     )
#         total_charges = OrderCharges.objects.filter(OrderNo=order_request_id, IsDeleted=False).aggregate(
#             total_amount=Sum('Rate'),
#             charge_count=Count('Rate')
#         )
#         return Response(
#             {
#                 "status_code": 200,
#                 "status": "success",
#                 "message": "Extra charge details fetched successfully.",
#                 "data": {
#                     "order_charges": order_charges,
#                     "total_extra_charge": total_charges['total_amount'],
#                     "count": total_charges['charge_count'],
#                     "formatted_extra_charge": convert_to_belgium_format(total_charges['total_amount'])
#                 }
#             },
#             status=status.HTTP_200_OK
#         )

class LoadPlanPDFView(APIView):
    def post(self, request, *args, **kwargs):
        loading_date = request.data.get('loading_date')
        if loading_date:
            orders = Orders.objects.filter(LoadingDate=loading_date,LoadPoint='PVS',IsDeleted=0).exclude(StatusId__in=[5, 1, 4])
            existing_order_numbers = list(orders.values_list('ExactOrderNo', flat=True)) if orders else []
            if orders:
                serializer = LoadPlanSerializer(orders, many=True, context={'request': request})
                time_blocks = {
                    '05H00-08H': ['05h - 06h', '06h - 07h', '07h - 08h'],
                    '08H00-11H': ['08h - 09h', '09h - 10h', '10h - 11h', '08:00 h', '10:00 h'],
                    '11H00-14H': ['11h - 12h', '12h - 13h', '13h - 14h', '12:00 h', ],
                    '14H00-17H': ['14h - 15h', '15h - 16h', '16h - 17h', '14:00 h', '16:00 h'],
                    '17H00-19H': ['17h - 18h', '18h - 19h', '18:00 h'] ,
                    '19H00-22H': ['20:00 h', '22:00 h'] ,
                    '8h': [] 
                }
                grouped = defaultdict(lambda: {'orders': [], 'total_quantity': 0.0, 'formatted_total_quantity': '0'})

                time_to_block = {
                    time: block
                    for block, times in time_blocks.items()
                    for time in times
                }

                for order in serializer.data:
                    # Normalize quantity once
                    raw_qty = order.get('Quantity')
                    quantity = round(float(raw_qty), 2) if raw_qty is not None else 0.0
                    order['Quantity'] = quantity
                    order['FormattedQuantity'] = convert_to_belgium_format(quantity)

                    print(repr(order['LoadingTime']), '->', time_to_block.get(order['LoadingTime'],  '8h'))

                    # Add to matched time block, or fallback to '8h'
                    block_name = time_to_block.get(order['LoadingTime'], '8h')

                    grouped[block_name]['orders'].append(order)
                    grouped[block_name]['total_quantity'] += quantity
                    grouped[block_name]['formatted_total_quantity'] = convert_to_belgium_format(
                        round(grouped[block_name]['total_quantity'], 2)
                    )


                if os.environ.get('DJANGO_ENV') != 'staging':
                    with connections['secondary'].cursor() as cursor:
                        placeholders = ', '.join(['%s'] * len(existing_order_numbers)) if existing_order_numbers else None

                        base_query = f"""
                                SELECT p.timeframe, p.ordernr, t1.ord_debtor_name AS OrderedCompany,
                                       t2.artcode AS Product, t2.esr_aantal AS Quantity
                                FROM tblplanning p
                                JOIN orkrg t1 ON p.ordernr = t1.ordernr
                                JOIN orsrg t2 ON t1.ordernr = t2.ordernr
                                WHERE p.datum = %s AND p.ordernr IS NOT NULL AND LTRIM(RTRIM(t2.regel)) = '1'
                            """

                        params = [loading_date]

                        if placeholders:
                            base_query += f" AND p.ordernr NOT IN ({placeholders})"
                            params.extend(existing_order_numbers)

                        cursor.execute(base_query, params)
                        columns = [col[0] for col in cursor.description]
                        sql_orders = [dict(zip(columns, row)) for row in cursor.fetchall()]
                        for order in sql_orders:
                            time = order.get('timeframe')
                            quantity = float(order.get('Quantity') or 0)
                            # Normalize keys to match ORM orders
                            normalized_order = {
                                'CustomerName': order.get('OrderedCompany'),
                                'ProductName': order.get('Product'),
                                'Quantity': round(quantity, 2),
                                'FormattedQuantity': convert_to_belgium_format(quantity),
                                'ExactOrderNo': order.get('ordernr')
                            }
                            if order.get('timeframe') == '05H00-08H00':
                                grouped['05H00-08H']['orders'].append(normalized_order)
                                grouped['05H00-08H']['total_quantity'] += normalized_order['Quantity']
                                grouped['05H00-08H']['formatted_total_quantity'] = convert_to_belgium_format(
                                    round(grouped['05H00-08H']['total_quantity'],2)
                                )
                            elif order.get('timeframe') == '08H00-11H00':
                                grouped['08H00-11H']['orders'].append(normalized_order)
                                grouped['08H00-11H']['total_quantity'] += normalized_order['Quantity']
                                grouped['08H00-11H']['formatted_total_quantity'] = convert_to_belgium_format(
                                    round(grouped['08H00-11H']['total_quantity'],2)
                                )
                            elif order.get('timeframe') == '11H00-14H00':
                                grouped['11H00-14H']['orders'].append(normalized_order)
                                grouped['11H00-14H']['total_quantity'] += normalized_order['Quantity']
                                grouped['11H00-14H']['formatted_total_quantity'] = convert_to_belgium_format(
                                    round(grouped['11H00-14H']['total_quantity'],2)
                                )
                            elif order.get('timeframe') == '14H00-17H00':
                                grouped['14H00-17H']['orders'].append(normalized_order)
                                grouped['14H00-17H']['total_quantity'] += normalized_order['Quantity']
                                grouped['14H00-17H']['formatted_total_quantity'] = convert_to_belgium_format(
                                    round(grouped['14H00-17H']['total_quantity'],2)
                                )
                            elif order.get('timeframe') == '17H00-19H30':
                                grouped['17H00-19H']['orders'].append(normalized_order)
                                grouped['17H00-19H']['total_quantity'] += normalized_order['Quantity']
                                grouped['17H00-19H']['formatted_total_quantity'] = convert_to_belgium_format(
                                    round(grouped['17H00-19H']['total_quantity'],2)
                                )
                            elif order.get('timeframe') == '19H00-22H':
                                grouped['19H00-22H']['orders'].append(normalized_order)
                                grouped['19H00-22H']['total_quantity'] += normalized_order['Quantity']
                                grouped['19H00-22H']['formatted_total_quantity'] = convert_to_belgium_format(
                                    round(grouped['19H00-22H']['total_quantity'],2)
                                )

                date_obj = datetime.strptime(loading_date, '%Y-%m-%d')
                formatted_date = date_obj.strftime('%d/%m/%Y')
                from collections import OrderedDict
                ordered_grouped = OrderedDict()
                for block in time_blocks.keys():
                    if block in grouped:
                        ordered_grouped[block] = grouped[block]
                context = {
                    'loading_date': formatted_date,
                    'grouped_orders': ordered_grouped
                }

                path_to_wkhtmltopdf = r"C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe"
                config = pdfkit.configuration(wkhtmltopdf=path_to_wkhtmltopdf)

                template = get_template("loadplan.html")
                html_string = template.render(context)

                options = {
                    'enable-local-file-access': None,
                    'quiet': ''
                }
                pdf = pdfkit.from_string(html_string, False, configuration=config, options=options)

                # Return response
                response = HttpResponse(pdf, content_type='application/pdf')
                response['Content-Disposition'] = 'filename="invoice.pdf"'
                return response

                # template = get_template("loadplan.html")
                # html = template.render(context)
                # # Create a PDF
                # response = HttpResponse(content_type='application/pdf')
                # response['Content-Disposition'] = 'filename="invoice.pdf"'
                # pisa_status = pisa.CreatePDF(io.StringIO(html), dest=response)
                #
                # # Return the response if successful, else error
                # if pisa_status.err:
                #     return HttpResponse('We had some errors <pre>' + html + '</pre>')
                # return response
            elif os.environ.get('DJANGO_ENV') != 'staging':
                    with connections['secondary'].cursor() as cursor:
                        placeholders = ', '.join(['%s'] * len(existing_order_numbers)) if existing_order_numbers else None
                        base_query = f"""
                                SELECT p.timeframe, p.ordernr, t1.ord_debtor_name AS OrderedCompany,
                                       t2.artcode AS Product, t2.esr_aantal AS Quantity
                                FROM tblplanning p
                                JOIN orkrg t1 ON p.ordernr = t1.ordernr
                                JOIN orsrg t2 ON t1.ordernr = t2.ordernr
                                WHERE p.datum = %s AND p.ordernr IS NOT NULL AND LTRIM(RTRIM(t2.regel)) = '1'
                            """

                        params = [loading_date]

                        if placeholders:
                            base_query += f" AND p.ordernr NOT IN ({placeholders})"
                            params.extend(existing_order_numbers)

                        cursor.execute(base_query, params)
                        columns = [col[0] for col in cursor.description]
                        sql_orders = [dict(zip(columns, row)) for row in cursor.fetchall()]
                        if sql_orders:
                            time_blocks = {
                                '05H00-08H': ['05h - 06h', '06h - 07h', '07h - 08h'],
                                '08H00-11H': ['08h - 09h', '09h - 10h', '10h - 11h', '08:00 h', '10:00 h', '8h00 - 14h00'],
                                '11H00-14H': ['11h - 12h', '12h - 13h', '13h - 14h', '12:00 h', ],
                                '14H00-17H': ['14h - 15h', '15h - 16h', '16h - 17h', '14:00 h', '16:00 h'],
                                '17H00-19H': ['17h - 18h', '18h - 19h', '18:00 h'] ,
                                '19H00-22H': ['20:00 h', '22:00 h'] ,
                            }
                            grouped = defaultdict(
                                lambda: {'orders': [], 'total_quantity': 0.0, 'formatted_total_quantity': '0'})
                            for order in sql_orders:
                                time = order.get('timeframe')
                                quantity = float(order.get('Quantity') or 0)
                                # Normalize keys to match ORM orders
                                normalized_order = {
                                    'CustomerName': order.get('OrderedCompany'),
                                    'ProductName': order.get('Product'),
                                    'Quantity': round(quantity, 2),
                                    'FormattedQuantity': convert_to_belgium_format(quantity),
                                    'ExactOrderNo': order.get('ordernr')
                                }
                                if order.get('timeframe') == '05H00-08H00':
                                    grouped['05H00-08H']['orders'].append(normalized_order)
                                    grouped['05H00-08H']['total_quantity'] += normalized_order['Quantity']
                                    grouped['05H00-08H']['formatted_total_quantity'] = convert_to_belgium_format(
                                        round(grouped['05H00-08H']['total_quantity'],2)
                                    )
                                elif order.get('timeframe') == '08H00-11H00':
                                    grouped['08H00-11H']['orders'].append(normalized_order)
                                    grouped['08H00-11H']['total_quantity'] += normalized_order['Quantity']
                                    grouped['08H00-11H']['formatted_total_quantity'] = convert_to_belgium_format(
                                        round(grouped['08H00-11H']['total_quantity'],2)
                                    )
                                elif order.get('timeframe') == '11H00-14H00':
                                    grouped['11H00-14H']['orders'].append(normalized_order)
                                    grouped['11H00-14H']['total_quantity'] += normalized_order['Quantity']
                                    grouped['11H00-14H']['formatted_total_quantity'] = convert_to_belgium_format(
                                        round(grouped['11H00-14H']['total_quantity'],2)
                                    )
                                elif order.get('timeframe') == '14H00-17H00':
                                    grouped['14H00-17H']['orders'].append(normalized_order)
                                    grouped['14H00-17H']['total_quantity'] += normalized_order['Quantity']
                                    grouped['14H00-17H']['formatted_total_quantity'] = convert_to_belgium_format(
                                        round(grouped['14H00-17H']['total_quantity'],2)
                                    )
                                elif order.get('timeframe') == '17H00-19H30':
                                    grouped['17H00-19H']['orders'].append(normalized_order)
                                    grouped['17H00-19H']['total_quantity'] += normalized_order['Quantity']
                                    grouped['17H00-19H']['formatted_total_quantity'] = convert_to_belgium_format(
                                        round(grouped['17H00-19H']['total_quantity'],2)
                                    )
                                elif order.get('timeframe') == '19H00-22H':
                                    grouped['19H00-22H']['orders'].append(normalized_order)
                                    grouped['19H00-22H']['total_quantity'] += normalized_order['Quantity']
                                    grouped['19H00-22H']['formatted_total_quantity'] = convert_to_belgium_format(
                                        round(grouped['19H00-22H']['total_quantity'],2)
                                    )
                            date_obj = datetime.strptime(loading_date, '%Y-%m-%d')
                            formatted_date = date_obj.strftime('%d/%m/%Y')
                            from collections import OrderedDict
                            ordered_grouped = OrderedDict()
                            for block in time_blocks.keys():
                                if block in grouped:
                                    ordered_grouped[block] = grouped[block]
                            context = {
                                'loading_date': formatted_date,
                                'grouped_orders': ordered_grouped
                            }

                            path_to_wkhtmltopdf = r"C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe"
                            config = pdfkit.configuration(wkhtmltopdf=path_to_wkhtmltopdf)

                            template = get_template("loadplan.html")
                            html_string  = template.render(context)

                            options = {
                                'enable-local-file-access': None,
                                'quiet': ''
                            }
                            pdf = pdfkit.from_string(html_string, False, configuration=config, options=options)

                            # Return response
                            response = HttpResponse(pdf, content_type='application/pdf')
                            response['Content-Disposition'] = 'filename="invoice.pdf"'
                            return response


                            # Create a PDF
                            # response = HttpResponse(content_type='application/pdf')
                            # response['Content-Disposition'] = 'filename="invoice.pdf"'
                            # pisa_status = pisa.CreatePDF(io.StringIO(html), dest=response)
                            #
                            # # Return the response if successful, else error
                            # if pisa_status.err:
                            #     return HttpResponse('We had some errors <pre>' + html + '</pre>')
                            # return response
                        else:
                            return Response({
                                "status_code": 404,
                                "status": "error",
                                "message": "No orders found"
                            }, status=status.HTTP_404_NOT_FOUND)
            else:
                return Response({
                    "status_code": 404,
                    "status": "error",
                    "message": "No orders found"
                }, status=status.HTTP_404_NOT_FOUND)
        else:
            return Response({
                "status_code": 400,
                "status": "error",
                "message": "loading_date is required"
            }, status=status.HTTP_400_BAD_REQUEST)


class SendLoadplanMailView(APIView):
    def post(self, request, *args, **kwargs):
        tomorrow = date.today() + timedelta(days=1)
        today = datetime.now().date()
        orders = Orders.objects.filter(LoadingDate=tomorrow,LoadPoint='PVS',IsDeleted=0).exclude(StatusId__in=[5, 1, 4])
        existing_order_numbers = list(orders.values_list('ExactOrderNo', flat=True)) if orders else []
        to_mails = os.getenv('LOADPLAN_MAIL_RECEIVER').split(',')

        if orders:
            serializer = LoadPlanSerializer(orders, many=True, context={'request': request})
            time_blocks = {
                    '05H00-08H': ['05h - 06h', '06h - 07h', '07h - 08h'],
                    '08H00-11H': ['08h - 09h', '09h - 10h', '10h - 11h', '08:00 h', '10:00 h'],
                    '11H00-14H': ['11h - 12h', '12h - 13h', '13h - 14h', '12:00 h', ],
                    '14H00-17H': ['14h - 15h', '15h - 16h', '16h - 17h', '14:00 h', '16:00 h'],
                    '17H00-19H': ['17h - 18h', '18h - 19h', '18:00 h'] ,
                    '19H00-22H': ['20:00 h', '22:00 h'] ,
                    '8h': []
                }
            grouped = defaultdict(lambda: {'orders': [], 'total_quantity': 0.0, 'formatted_total_quantity': '0'})

            time_to_block = {
                    time: block
                    for block, times in time_blocks.items()
                    for time in times
                }

            for order in serializer.data:
                raw_qty = order.get('Quantity')
                quantity = round(float(raw_qty), 2) if raw_qty is not None else 0.0
                order['Quantity'] = quantity
                order['FormattedQuantity'] = convert_to_belgium_format(quantity)

                # Add to matched time block, or fallback to '8h'
                block_name = time_to_block.get(order['LoadingTime'], '8h')

                grouped[block_name]['orders'].append(order)
                grouped[block_name]['total_quantity'] += quantity
                grouped[block_name]['formatted_total_quantity'] = convert_to_belgium_format(
                    round(grouped[block_name]['total_quantity'], 2)
                )
            if os.environ.get('DJANGO_ENV') != 'staging':
                with connections['secondary'].cursor() as cursor:
                    placeholders = ', '.join(['%s'] * len(existing_order_numbers)) if existing_order_numbers else None

                    base_query = f"""
                                           SELECT p.timeframe, p.ordernr, t1.ord_debtor_name AS OrderedCompany,
                                                  t2.artcode AS Product, t2.esr_aantal AS Quantity
                                           FROM tblplanning p
                                           JOIN orkrg t1 ON p.ordernr = t1.ordernr
                                           JOIN orsrg t2 ON t1.ordernr = t2.ordernr
                                           WHERE p.datum = %s AND p.ordernr IS NOT NULL AND LTRIM(RTRIM(t2.regel)) = '1'
                                       """

                    params = [tomorrow]

                    if placeholders:
                        base_query += f" AND p.ordernr NOT IN ({placeholders})"
                        params.extend(existing_order_numbers)

                    cursor.execute(base_query, params)
                    columns = [col[0] for col in cursor.description]
                    sql_orders = [dict(zip(columns, row)) for row in cursor.fetchall()]
                    for order in sql_orders:
                        time = order.get('timeframe')
                        quantity = float(order.get('Quantity') or 0)
                        # Normalize keys to match ORM orders
                        normalized_order = {
                            'CustomerName': order.get('OrderedCompany'),
                            'ProductName': order.get('Product'),
                            'Quantity': round(quantity, 2),
                            'FormattedQuantity': convert_to_belgium_format(quantity),
                            'ExactOrderNo': order.get('ordernr')
                        }
                        if order.get('timeframe') == '05H00-08H00':
                            grouped['05H00-08H']['orders'].append(normalized_order)
                            grouped['05H00-08H']['total_quantity'] += normalized_order['Quantity']
                            grouped['05H00-08H']['formatted_total_quantity'] = convert_to_belgium_format(
                                round(grouped['05H00-08H']['total_quantity'], 2)
                            )
                        elif order.get('timeframe') == '08H00-11H00':
                            grouped['08H00-11H']['orders'].append(normalized_order)
                            grouped['08H00-11H']['total_quantity'] += normalized_order['Quantity']
                            grouped['08H00-11H']['formatted_total_quantity'] = convert_to_belgium_format(
                                round(grouped['08H00-11H']['total_quantity'], 2)
                            )
                        elif order.get('timeframe') == '11H00-14H00':
                            grouped['11H00-14H']['orders'].append(normalized_order)
                            grouped['11H00-14H']['total_quantity'] += normalized_order['Quantity']
                            grouped['11H00-14H']['formatted_total_quantity'] = convert_to_belgium_format(
                                round(grouped['11H00-14H']['total_quantity'], 2)
                            )
                        elif order.get('timeframe') == '14H00-17H00':
                            grouped['14H00-17H']['orders'].append(normalized_order)
                            grouped['14H00-17H']['total_quantity'] += normalized_order['Quantity']
                            grouped['14H00-17H']['formatted_total_quantity'] = convert_to_belgium_format(
                                round(grouped['14H00-17H']['total_quantity'], 2)
                            )
                        elif order.get('timeframe') == '17H00-19H30':
                            grouped['17H00-19H']['orders'].append(normalized_order)
                            grouped['17H00-19H']['total_quantity'] += normalized_order['Quantity']
                            grouped['17H00-19H']['formatted_total_quantity'] = convert_to_belgium_format(
                                round(grouped['17H00-19H']['total_quantity'], 2)
                            )
                        elif order.get('timeframe') == '19H00-22H':
                            grouped['19H00-22H']['orders'].append(normalized_order)
                            grouped['19H00-22H']['total_quantity'] += normalized_order['Quantity']
                            grouped['19H00-22H']['formatted_total_quantity'] = convert_to_belgium_format(
                                round(grouped['19H00-22H']['total_quantity'], 2)
                            )

            formatted_date = tomorrow.strftime('%d/%m/%Y')
            from collections import OrderedDict
            ordered_grouped = OrderedDict()
            for block in time_blocks.keys():
                if block in grouped:
                    ordered_grouped[block] = grouped[block]

            context = {
                'loading_date': formatted_date,
                'grouped_orders': ordered_grouped
            }

            path_to_wkhtmltopdf = r"C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe"
            config = pdfkit.configuration(wkhtmltopdf=path_to_wkhtmltopdf)

            template = get_template("loadplan.html")
            html_string = template.render(context)

            options = {
                'enable-local-file-access': None,
                'quiet': ''
            }
            pdf = pdfkit.from_string(html_string, False, configuration=config, options=options)

            # response = HttpResponse(content_type='application/pdf')
            # response['Content-Disposition'] = 'filename="invoice.pdf"'
            # pisa_status = pisa.CreatePDF(io.StringIO(html), dest=response)


            # template = get_template("loadplan.html")
            # html = template.render(context)
            # result = io.BytesIO()
            # pisa_status = pisa.CreatePDF(io.StringIO(html), dest=result)
            #
            # if pisa_status.err:
            #     return Response({
            #         "status_code": 500,
            #         "status": "failed",
            #         "message": "Error generating PDF",
            #         "data": None
            #     }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            current_time = now().strftime("%Y-%m-%d %H:%M")
            body = (
                "Hi Team,\n\n"
                "Please find attached the load plan for tomorrow("+str(tomorrow)+"), generated via OrderPro.\n\n"
                f"This includes all orders planned for loading tomorrow, as of {current_time}.\n\n"
                "Kind regards,\n"
                "OrderPro"
            )

            email = EmailMessage(
                subject='Order Pro Load Plan : '+str(tomorrow),
                body=body,
                from_email=os.getenv('EMAIL_HOST_USER'),
                cc = ['ashik.os@tycaninc.com', 'parvathy@tycaninc.com'],
                to=to_mails
            )
            email.attach('loadplan : '+str(tomorrow)+'.pdf', pdf, 'application/pdf')
            try:
                email.send()
                email_log = EmailLog(
                    sender=os.getenv('EMAIL_HOST_USER'),
                    recipient=to_mails,
                    cc='ashik.os@tycaninc.com, parvathy@tycaninc.com',
                    subject='Load Plan: '+str(tomorrow),
                    body=body,
                    sent_at=now(),
                    status="success",
                    triggered_by="27",
                    order_id="",
                    type="loadplan daily mail",
                    receipient_id=0
                )
                encoded_pdf = base64.b64encode(pdf).decode('utf-8')
                email_log.attachment = encoded_pdf
                email_log.save()
                return Response({
                    "status_code": 200,
                    "status": "success",
                    "message": "Plan mailed successfully"
                }, status=status.HTTP_200_OK)
            except Exception as e:
                email_log = EmailLog(
                    sender=os.getenv('EMAIL_HOST_USER'),
                    recipient=os.getenv('LOADPLAN_MAIL_RECEIVER'),
                    cc='ashik.os@tycaninc.com, parvathy@tycaninc.com',
                    subject='Load Plan: ' + str(tomorrow),
                    body=str(e),
                    sent_at=now(),
                    status="failed",
                    triggered_by="27",
                    order_id="",
                    type="loadplan daily mail",
                    receipient_id=0
                )
                pdf_data = pdf
                email_log.attachment.save(f"loadplan_{str(tomorrow)}.pdf", ContentFile(pdf_data))
                email_log.save()
                return Response({
                    "status_code": 500,
                    "status": "failed",
                    "message": "An error occurred", "error": str(e),
                    "data": None
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        elif os.environ.get('DJANGO_ENV') != 'staging':
            with connections['secondary'].cursor() as cursor:
                placeholders = ', '.join(['%s'] * len(existing_order_numbers)) if existing_order_numbers else None

                base_query = f"""
                                       SELECT p.timeframe, p.ordernr, t1.ord_debtor_name AS OrderedCompany,
                                              t2.artcode AS Product, t2.esr_aantal AS Quantity
                                       FROM tblplanning p
                                       JOIN orkrg t1 ON p.ordernr = t1.ordernr
                                       JOIN orsrg t2 ON t1.ordernr = t2.ordernr
                                       WHERE p.datum = %s AND p.ordernr IS NOT NULL AND LTRIM(RTRIM(t2.regel)) = '1'
                                   """

                params = [tomorrow]

                if placeholders:
                    base_query += f" AND p.ordernr NOT IN ({placeholders})"
                    params.extend(existing_order_numbers)

                cursor.execute(base_query, params)
                columns = [col[0] for col in cursor.description]
                sql_orders = [dict(zip(columns, row)) for row in cursor.fetchall()]
                if sql_orders:
                    time_blocks = {
                    '05H00-08H': ['05h - 06h', '06h - 07h', '07h - 08h'],
                    '08H00-11H': ['08h - 09h', '09h - 10h', '10h - 11h', '08:00 h', '10:00 h'],
                    '11H00-14H': ['11h - 12h', '12h - 13h', '13h - 14h', '12:00 h', ],
                    '14H00-17H': ['14h - 15h', '15h - 16h', '16h - 17h', '14:00 h', '16:00 h'],
                    '17H00-19H': ['17h - 18h', '18h - 19h', '18:00 h'] ,
                    '19H00-22H': ['20:00 h', '22:00 h'] ,
                }
                    grouped = defaultdict(
                        lambda: {'orders': [], 'total_quantity': 0.0, 'formatted_total_quantity': '0'})

                    for order in sql_orders:
                        time = order.get('timeframe')
                        quantity = float(order.get('Quantity') or 0)
                        normalized_order = {
                            'CustomerName': order.get('OrderedCompany'),
                            'ProductName': order.get('Product'),
                            'Quantity': round(quantity, 2),
                            'FormattedQuantity': convert_to_belgium_format(quantity),
                            'ExactOrderNo': order.get('ordernr')
                        }
                        if order.get('timeframe') == '05H00-08H00':
                            grouped['05H00-08H']['orders'].append(normalized_order)
                            grouped['05H00-08H']['total_quantity'] += normalized_order['Quantity']
                            grouped['05H00-08H']['formatted_total_quantity'] = convert_to_belgium_format(
                                round(grouped['05H00-08H']['total_quantity'], 2)
                            )
                        elif order.get('timeframe') == '08H00-11H00':
                            grouped['08H00-11H']['orders'].append(normalized_order)
                            grouped['08H00-11H']['total_quantity'] += normalized_order['Quantity']
                            grouped['08H00-11H']['formatted_total_quantity'] = convert_to_belgium_format(
                                round(grouped['08H00-11H']['total_quantity'], 2)
                            )
                        elif order.get('timeframe') == '11H00-14H00':
                            grouped['11H00-14H']['orders'].append(normalized_order)
                            grouped['11H00-14H']['total_quantity'] += normalized_order['Quantity']
                            grouped['11H00-14H']['formatted_total_quantity'] = convert_to_belgium_format(
                                round(grouped['11H00-14H']['total_quantity'], 2)
                            )
                        elif order.get('timeframe') == '14H00-17H00':
                            grouped['14H00-17H']['orders'].append(normalized_order)
                            grouped['14H00-17H']['total_quantity'] += normalized_order['Quantity']
                            grouped['14H00-17H']['formatted_total_quantity'] = convert_to_belgium_format(
                                round(grouped['14H00-17H']['total_quantity'], 2)
                            )
                        elif order.get('timeframe') == '17H00-19H30':
                            grouped['17H00-19H']['orders'].append(normalized_order)
                            grouped['17H00-19H']['total_quantity'] += normalized_order['Quantity']
                            grouped['17H00-19H']['formatted_total_quantity'] = convert_to_belgium_format(
                                round(grouped['17H00-19H']['total_quantity'], 2)
                            )
                        elif order.get('timeframe') == '19H00-22H':
                            grouped['19H00-22H']['orders'].append(normalized_order)
                            grouped['19H00-22H']['total_quantity'] += normalized_order['Quantity']
                            grouped['19H00-22H']['formatted_total_quantity'] = convert_to_belgium_format(
                                round(grouped['19H00-22H']['total_quantity'], 2)
                            )
                    formatted_date = tomorrow.strftime('%d/%m/%Y')
                    from collections import OrderedDict
                    ordered_grouped = OrderedDict()
                    for block in time_blocks.keys():
                        if block in grouped:
                            ordered_grouped[block] = grouped[block]

                    context = {
                        'loading_date': formatted_date,
                        'grouped_orders': ordered_grouped
                    }

                    path_to_wkhtmltopdf = r"C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe"
                    config = pdfkit.configuration(wkhtmltopdf=path_to_wkhtmltopdf)

                    template = get_template("loadplan.html")
                    html_string = template.render(context)

                    options = {
                        'enable-local-file-access': None,
                        'quiet': ''
                    }
                    pdf = pdfkit.from_string(html_string, False, configuration=config, options=options)

                    # template = get_template("loadplan.html")
                    # html = template.render(context)
                    # result = io.BytesIO()
                    # pisa_status = pisa.CreatePDF(io.StringIO(html), dest=result)
                    #
                    # if pisa_status.err:
                    #     return Response({
                    #         "status_code": 500,
                    #         "status": "failed",
                    #         "message": "Error generating PDF",
                    #         "data": None
                    #     }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
                    current_time = now().strftime("%Y-%m-%d %H:%M")
                    body = (
                            "Hi Team,\n\n"
                            "Please find attached the load plan for tomorrow(" + str(
                        tomorrow) + "), generated via OrderPro.\n\n"
                                 f"This includes all orders planned for loading tomorrow, as of {current_time}.\n\n"
                                 "Kind regards,\n"
                                 "OrderPro"
                    )
                    email = EmailMessage(
                        subject='Order Pro Load Plan : ' + str(tomorrow),
                        body=body,
                        from_email=os.getenv('EMAIL_HOST_USER'),
                        cc=['ashmi.ma@tycaninc.com'],
                        to=[os.getenv('LOADPLAN_MAIL_RECEIVER')]
                    )
                    email.attach('loadplan : ' + str(tomorrow) + '.pdf', pdf, 'application/pdf')
                    try:
                        email.send()
                        email_log = EmailLog(
                            sender=os.getenv('EMAIL_HOST_USER'),
                            recipient=os.getenv('LOADPLAN_MAIL_RECEIVER'),
                            cc='ashik.os@tycaninc.com, parvathy@tycaninc.com',
                            subject='Load Plan: ' + str(tomorrow),
                            body=body,
                            sent_at=now(),
                            status="success",
                            triggered_by="27",
                            order_id="",
                            type="loadplan daily mail",
                            receipient_id=0
                        )
                        print(":data saved successfully" )
                        encoded_pdf = base64.b64encode(pdf).decode('utf-8')
                        email_log.attachment = encoded_pdf
                        email_log.save()
                        return Response({
                            "status_code": 200,
                            "status": "success",
                            "message": "Plan mailed successfully"
                        }, status=status.HTTP_200_OK)
                    except Exception as e:
                        email_log = EmailLog(
                            sender=os.getenv('EMAIL_HOST_USER'),
                            recipient=os.getenv('LOADPLAN_MAIL_RECEIVER'),
                            cc='ashik.os@tycaninc.com, parvathy@tycaninc.com',
                            subject='Load Plan: ' + str(tomorrow),
                            body=str(e),
                            sent_at=now(),
                            status="failed",
                            triggered_by="27",
                            order_id="",
                            type="loadplan daily mail",
                            receipient_id=0
                        )
                        encoded_pdf = base64.b64encode(pdf).decode('utf-8')
                        email_log.attachment = encoded_pdf
                        email_log.save()
                        return Response({
                            "status_code": 500,
                            "status": "failed",
                            "message": "An error occurred", "error": str(e),
                            "data": None
                        }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
                else:
                    EmailLog.objects.create(
                        sender=os.getenv('EMAIL_HOST_USER'),
                        recipient=os.getenv('LOADPLAN_MAIL_RECEIVER'),
                        cc='ashik.os@tycaninc.com, parvathy@tycaninc.com',
                        subject='Load Plan: ' + str(tomorrow),
                        body="No orders found",
                        sent_at=now(),
                        status="failed",
                        triggered_by="27",
                        order_id="",
                        type="loadplan daily mail",
                        receipient_id=0
                    )
        else:
            EmailLog.objects.create(
                sender=os.getenv('EMAIL_HOST_USER'),
                recipient=os.getenv('LOADPLAN_MAIL_RECEIVER'),
                cc='ashik.os@tycaninc.com, parvathy@tycaninc.com',
                subject='Load Plan: ' + str(tomorrow),
                body="No orders found",
                sent_at=now(),
                status="failed",
                triggered_by="27",
                order_id="",
                type="loadplan daily mail",
                receipient_id=0
            )
        return Response({
            "status_code": 404,
            "status": "error",
            "message": "No orders found"
        }, status=status.HTTP_404_NOT_FOUND)


class GenerateXMLAPIView(APIView):
    def post(self, request, *args, **kwargs):
        if request.data.get('all_checked') is not None:
            all_checked = request.data.get('all_checked')
            if all_checked == 1:
                # Filter conditions setup
                filter_conditions = Q(IsDeleted=False)

                # Apply additional filters based on request parameters
                if request.data.get('status_id') is not None:
                    filter_conditions &= Q(StatusId=request.data.get('status_id'))
                if request.data.get('product_id') is not None:
                    filter_conditions &= Q(ProductId=request.data.get('product_id'))
                if request.data.get('created_date_from') and request.data.get('created_date_to'):
                    new_created_date_to = datetime.strptime(request.data.get('created_date_to'),
                                                            '%Y-%m-%d') + timedelta(
                        days=1)
                    new_created_date_to_str = new_created_date_to.strftime('%Y-%m-%d')
                    filter_conditions &= Q(
                        CreatedAt__range=[request.data.get('created_date_from'), new_created_date_to_str])
                if request.data.get('client_id') is not None:
                    filter_conditions &= Q(OrderedCustomerId=request.data.get('client_id')) | Q(
                        BillToCustomerId=request.data.get('client_id')) | Q(
                        DeliveryCustomerId=request.data.get('client_id'))
                if request.data.get('delivery_date_from') and request.data.get('delivery_date_to'):
                    filter_conditions &= Q(
                        DeliveryDate__range=[request.data.get('delivery_date_from'),
                                             request.data.get('delivery_date_to')])
                if request.data.get('search_query') is not None:
                    search_query = request.data.get('search_query')
                    filter_conditions &= Q(
                        Q(ExactOrderNo__icontains=search_query) |
                        Q(OrderedCustomerName__icontains=search_query) |
                        Q(BillToCustomerName__icontains=search_query) |
                        Q(DeliveryCustomerName__icontains=search_query) |
                        Q(ProductName__icontains=search_query)
                    )
                order_ids = Orders.objects.filter(filter_conditions).values_list('OrderNo', flat=True)
                unchecked_order_ids = request.data.get('unchecked_order_ids', [])
                if unchecked_order_ids:  # Check if unchecked_order_ids is present and not empty
                    # Iterate through each value and remove it from all_order_ids if it exists
                    unchecked_order_ids = list(unchecked_order_ids)  # Ensure it's a list
                    filtered_order_ids = [order_id for order_id in order_ids if order_id not in unchecked_order_ids]
                else:
                    filtered_order_ids = order_ids
                order_ids = filtered_order_ids
            else:
                order_id = request.data.get('order_id')
                if not order_id:
                    return Response({
                        'status': 'error',
                        'status_code': 400,
                        'message': 'No order_id provided.',
                    }, status=400)
        else:
            order_id = request.data.get('order_id')
            if not order_id:
                return Response({
                    'status': 'error',
                    'status_code': 400,
                    'message': 'No order_id provided.',
                }, status=400)
        # Create an in-memory ZIP file
        zip_buffer = io.BytesIO()

        order_details = Orders.objects.filter(OrderNo=order_id, IsDeleted=False).first()

        # Use the zipfile module to write into the in-memory zip buffer
        # with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file:
        #     try:
        #         order_details = Orders.objects.filter(OrderNo=order_id, IsDeleted=False).first()
        #         if order_details:
        #             order_request_serializer = OrderXMLSerializerNew(order_details, context={'request': request})
        #             if order_request_serializer is not None:
        #                 root = ET.Element("eExact", xmlns_xsi="http://www.w3.org/2001/XMLSchema-instance",
        #                                   xsi_noNamespaceSchemaLocation="eExact-Schema.xsd")
        #
        #                 orders = ET.SubElement(root, "Orders")
        #
        #                 # Order element
        #                 order_elem = ET.SubElement(orders, "Order", type="V",
        #                                            number=str(order_request_serializer.data['ExactOrderNo']),code=str(order_request_serializer.data['InvoiceCode']))
        #
        #                 # Basic order data
        #                 ET.SubElement(order_elem, "Description").text = ""
        #                 ET.SubElement(order_elem, "Reference1").text = ""
        #                 ET.SubElement(order_elem, "Reference2").text = ""
        #                 ET.SubElement(order_elem, "Reference3").text = ""
        #
        #                 order_request = OrderRequests.objects.filter(Id=order_id).first()
        #                 purchase_order_no = order_request.PurchaseOrderNo if order_request else None
        #
        #                 if purchase_order_no:
        #                     ET.SubElement(order_elem, "YourRef").text = purchase_order_no
        #                 if os.environ.get('DJANGO_ENV') == 'staging':
        #                     payment_details = ('EUR', '04', '5', 'CIP')
        #                 else:
        #                     with connections['secondary'].cursor() as cursor:
        #                         query = f"SELECT currency,paymentcondition,vatcode,deliverymethod FROM cicmpy WHERE TRIM(debnr) = {order_request_serializer.data['OrderedByCode']}"
        #                         cursor.execute(query)
        #                         payment_details = cursor.fetchone()
        #                         if payment_details is None:
        #                             payment_details = ('EUR', '', '', '')
        #                         else:
        #                             payment_details = tuple(
        #                                 item.strip() if isinstance(item, str) else item for item in payment_details)
        #                 ET.SubElement(order_elem, "Currency", code=str(payment_details[0]))
        #                 ET.SubElement(order_elem, "CalcIncludeVAT")
        #                 ET.SubElement(order_elem, "Resource", number=str(order_request_serializer.data['ResourceCode']))
        #
        #                 # OrderedBy section
        #                 ordered_by = ET.SubElement(order_elem, "OrderedBy")
        #                 ET.SubElement(ordered_by, "Debtor", code=str(order_request_serializer.data['OrderedByCode']))
        #                 ET.SubElement(ordered_by, "Date").text = date.today().strftime('%Y-%m-%d')
        #
        #                 # DeliverTo section
        #                 deliver_to = ET.SubElement(order_elem, "DeliverTo")
        #                 ET.SubElement(deliver_to, "Debtor", code=str(order_request_serializer.data['ShipToCode']))
        #                 ET.SubElement(deliver_to, "Date").text = order_request_serializer.data['LoadingDate']
        #
        #                 # InvoiceTo
        #                 ET.SubElement(order_elem, "InvoiceTo").append(ET.Element("Debtor", code=str(order_request_serializer.data['InvoiceToCode'])))
        #
        #                 ET.SubElement(order_elem, "Warehouse", code=str(order_request_serializer.data['WareHouseCode']))
        #                 ET.SubElement(order_elem, "PaymentMethod", code="B")
        #                 ET.SubElement(order_elem, "PaymentCondition", code=str(payment_details[1]))
        #                 ET.SubElement(order_elem, "DeliveryMethod", code=order_request_serializer.data['IncoTerm'])
        #                 ET.SubElement(order_elem, "Costcenter", code=order_request_serializer.data['CostCenter'])
        #                 ET.SubElement(order_elem, "Selection", code=str(order_request_serializer.data['SelectionCode']))
        #                 ET.SubElement(order_elem, "Freight")
        #
        #                 # FreeFields
        #                 free_fields = ET.SubElement(order_elem, "FreeFields")
        #                 free_texts = ET.SubElement(free_fields, "FreeTexts")
        #                 ET.SubElement(free_texts, "FreeText", number="1").text = ""
        #                 ET.SubElement(free_texts, "FreeText", number="2").text = ""
        #                 ET.SubElement(free_texts, "FreeText", number="3").text = ""
        #
        #                 free_numbers = ET.SubElement(free_fields, "FreeNumbers")
        #                 # if order_request_serializer.data['IncoTerm'] == "DDP":
        #                 ET.SubElement(free_numbers, "FreeNumber", number="4").text = str(order_request_serializer.data['TransportPrice'])
        #                 # else:
        #                 #     ET.SubElement(free_numbers, "FreeNumber", number="4").text = ""
        #                 ET.SubElement(free_numbers, "FreeNumber", number="5").text = ""
        #
        #                 ET.SubElement(order_elem, "ApplyShippingCharges").text = "0"
        #
        #                 # OrderLine
        #                 if os.environ.get('DJANGO_ENV') == 'staging':
        #                     product_details = ('TEST PROUDCT DESCRIPTION', 'TEST PRODUCT')
        #                 else:
        #                     with connections['secondary'].cursor() as cursor:
        #                         query = f"SELECT description,itemcode  FROM items WHERE  itemcode LIKE '%{order_request_serializer.data['ArticleCode']}%'"
        #                         cursor.execute(query)
        #                         product_details = cursor.fetchone()
        #                 order_line = ET.SubElement(order_elem, "OrderLine", lineNo="1")
        #                 if product_details is not None:
        #                     if product_details[1] =='31112 H2SO4 T 96 % SADACI':
        #                         product_code = '31112 H2SO4 T 96 % MOLYMET'
        #                         product_description = product_details[0]
        #                     elif product_details[1] == '31112 - H2SO4 T 96% MOLYMET':
        #                         product_code = '31112 H2SO4 T 96 % MOLYMET'
        #                         product_description = product_details[0]
        #                     elif product_details[1] == '30104 SULF.T. 96% TM':
        #                         product_code = '30104 H2SO4 TECH 94%'
        #                         product_description = 'ZWAVELZUUR 94% DRUG PRECURSORS'
        #                     else:
        #                         product_code = product_details[1]
        #                         product_description = product_details[0]
        #                     ET.SubElement(order_line, "Description").text = str(product_description)
        #                     ET.SubElement(order_line, "Item", code=str(product_code))
        #                 else:
        #                     ET.SubElement(order_line, "Description").text = ""
        #                     ET.SubElement(order_line, "Item", code="")
        #                 ET.SubElement(order_line, "Quantity").text = str(convert_to_belgium_format(order_request_serializer.data['Quantity']))
        #
        #                 unit = ET.SubElement(order_line, "Unit", unit="TO")
        #                 ET.SubElement(unit, "MultiDescriptions")  # Empty tag
        #                 price = ET.SubElement(order_line, "Price", type="S")
        #                 ET.SubElement(price, "Currency", code=str(payment_details[0]))
        #                 ET.SubElement(price, "Value").text = str(order_request_serializer.data['Price'])
        #                 ET.SubElement(price, "VAT", code=str(payment_details[2]))
        #                 amount = ET.SubElement(order_line, "Amount", type="S")
        #                 ET.SubElement(amount, "Currency", code=str(payment_details[0]))
        #                 ET.SubElement(amount, "Value").text = ""
        #
        #                 discount = ET.SubElement(order_line, "Discount")
        #                 ET.SubElement(discount, "Percentage").text = "0"
        #                 delivery = ET.SubElement(order_line, "Delivery")
        #                 ET.SubElement(delivery, "Date").text = order_request_serializer.data['LoadingDate']
        #                 ET.SubElement(order_line, "Warehouse", code=str(order_request_serializer.data['WareHouseCode']))
        #                 ET.SubElement(order_line, "Costcenter", code=order_request_serializer.data['CostCenter'])
        #                 if order_request_serializer.data['IncoTerm'] == "FCA" or order_request_serializer.data['IncoTerm'] == "EXW":
        #                     # ET.SubElement(order_line, "Instruction",datetime.strptime(order_request_serializer.data['LoadingDate'], '%Y-%m-%d').strftime('%d/%m/%Y')+' '+order_request_serializer.data['IncoTerm'])
        #                     ET.SubElement(order_line, "Instruction").text =datetime.strptime(order_request_serializer.data['LoadingDate'], '%Y-%m-%d').strftime('%d/%m/%Y')+' '+order_request_serializer.data['IncoTerm']
        #                 else:
        #                     delivery_time_interval = OrderRequests.objects.filter(Id=order_id).values_list(
        #                         'DeliveryTimeInterval',flat=True).first()
        #                     # ET.SubElement(order_line, "Instruction",datetime.strptime(order_request_serializer.data['DeliveryDate'], '%Y-%m-%d').strftime('%d/%m/%Y')+' '+delivery_time_interval)
        #                     ET.SubElement(order_line, "Instruction").text =datetime.strptime(order_request_serializer.data['DeliveryDate'], '%Y-%m-%d').strftime('%d/%m/%Y')+' '+delivery_time_interval
        #
        #                 if order_request.Information:
        #                     information_string = f"{order_request.Information} {datetime.strptime(order_request_serializer.data['LoadingDate'], '%Y-%m-%d').strftime('%d/%m/%Y')}"
        #                     order_line2 = ET.SubElement(order_elem, "OrderLine", lineNo="2")
        #                     ET.SubElement(order_line2, "Text").text = information_string
        #
        #                 # Convert the XML to a buffer
        #                 tree = ET.ElementTree(root)
        #                 xml_buffer = io.BytesIO()
        #
        #                 # tree.write(xml_buffer, encoding='utf-8', xml_declaration=True)
        #                 # xml_buffer.seek(0)  # Ensure we are at the start of the buffer
        #                 #
        #                 # # Add the XML to the zip file, named according to the order ID
        #                 # zip_file.writestr(f"{order_request_serializer.data['ExactOrderNo']}.xml",
        #                 #                   xml_buffer.read())
        #                 # Write XML content to buffer
        #                 tree.write(xml_buffer, encoding='utf-8', xml_declaration=True)
        #                 xml_buffer.seek(0)  # Ensure we are at the start of the buffer
        #
        #                 # Generate filename from order number
        #                 filename = f"{order_request_serializer.data['ExactOrderNo']}.xml"
        #
        #                 # Return as downloadable file
        #                 response = HttpResponse(xml_buffer.read(), content_type='application/xml')
        #                 response['Content-Disposition'] = f'attachment; filename="{filename}"'
        #                 return response
        #             else:
        #                 return Response({
        #                     "status_code": 404,
        #                     "status": "error",
        #                     "message": "No sufficient order details found"
        #                 }, status=status.HTTP_404_NOT_FOUND)
        #         else:
        #             return Response({
        #                 "status_code": 404,
        #                 "status": "error",
        #                 "message": "No order details found"
        #             }, status=status.HTTP_404_NOT_FOUND)
        #         find_me = 1
        #     except Exception as e:
        #         # Return a response with an error if there's an issue with processing a particular order
        #         return Response({
        #             'status': 'error',
        #             'status_code': 500,
        #             'message': f"Error processing order ID {order_id}: {str(e)}"
        #         }, status=500)

        xml_buffer, filename = purchase_utils.generate_xml(order_id, order_details, request)


        # Return as downloadable file
        response = HttpResponse(xml_buffer.read(), content_type='application/xml')
        response['Content-Disposition'] = f'attachment; filename="{filename}"'

        return response

        # # Ensure the zip buffer is at the start before reading it
        # zip_buffer.seek(0)
        #
        # # Return the zip file as a response with the appropriate headers
        # response = HttpResponse(zip_buffer.read(), content_type='application/zip')
        # response['Content-Disposition'] = 'attachment; filename="orders.zip"'
        #
        # return response

class ServeImageView(APIView):
    def get(self, request, filename):
        # Construct the file path
        file_path = os.path.join(settings.IMAGE_FILE_PATH, filename)

        # Check if the file exists
        if not os.path.exists(file_path):
            return Response({
                "status_code": 404,
                "status": "error",
                "message": "File not found"
            }, status=status.HTTP_404_NOT_FOUND)
        try:
            # Guess the content type of the file
            content_type, _ = mimetypes.guess_type(file_path)
            if content_type is None:
                content_type = 'application/octet-stream'  # fallback

            # Serve the file
            response = FileResponse(open(file_path, 'rb'), content_type=content_type)
            response['Content-Disposition'] = f'inline; filename="{filename}"'
            return response
        except Exception as e:
            return Response({
                "status_code": 500,
                "status": "error",
                "message": f"Error serving file: {str(e)}"
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

# class IncoTermsListView(APIView):
#     def post(self, request, *args, **kwargs):
#         data = request.data
#         required_fields = [
#             "product_id","packaging","deliver_to","ordered_by", "bill_to","quantity","loading_date","loading_slot_id"
#         ]
#         # Iterate through each field and check if it's null or empty
#         for field in required_fields:
#             value = data.get(field)
#             # If any required field is missing or empty
#             if value is None or (isinstance(value, str) and value.strip() == ''):
#                 # Return error response and stop the process
#                 return Response({
#                     "status_code": 400,
#                     "status": "error",
#                     "message": f"The field '{field}' is required and cannot be null or empty."
#                 }, status=status.HTTP_400_BAD_REQUEST)
#         product_article_code = get_product_articlecode(request.headers.get('x-auth-token'),
#                                                        data.get('product_id'))
#         deliver_to_address_code = get_address_code_from_id(request.headers.get('x-auth-token'),
#                                                            data.get('deliver_to'))
#         formatted_quantity = Decimal(str(data.get('quantity'))).quantize(Decimal('0.00'))
#         price_master = PriceMaster.objects.filter(
#             ArticleCode=product_article_code,
#             Packaging='Bulk',
#             ExactERPAddressId=deliver_to_address_code,
#             IsDeleted=0,
#             MinQuantity__lte=formatted_quantity,  # Less than or equal to Min Quantity
#         ).filter(
#             Q(ValidityStartDate__lte=data.get('loading_date')) & Q(
#                 ValidityEndDate__gte=data.get('loading_date'))  # Date range
#         ).order_by(
#             '-MinQuantity')  # Order by MinQuantity in descending order and get the first row ie pick row row with highest quantity in case of mutiple rows
#         incoterm_data = []
#         if price_master.count == 0 :
#             price_master = PriceMaster.objects.filter(  # check without minimum quantity conditions
#                 ArticleCode=product_article_code,
#                 Packaging='Bulk',
#                 ExactERPAddressId=deliver_to_address_code,
#                 IsDeleted=0,
#             ).filter(
#                 Q(MinQuantity__isnull=True)
#             ).filter(
#                 Q(ValidityStartDate__lte=data.get('loading_date')) & Q(
#                     ValidityEndDate__gte=data.get('loading_date'))  # Date range
#             )
#         if price_master.count > 0: # if incoterm and price found from pricemaster table
#             if price_master.count == 1:  # single result so pass it as system recommended incoterm
#                 incoterm_data['Id'] = price_master.IncoTermID
#                 incoterm_data['Code'] = price_master.IncoTerm
#                 incoterm_data['Price'] = convert_to_belgium_format(price_master.Price)
#                 incoterm_data['Quarter'] = price_master.QuarterName
#             else:  # multiple incoterms found so check latest similar order
#                 #check against which incoterm transaction present.if prsesnt for all take latest ,if not present take the first one
#
#                 for price_data in price_master:
#
#         else: #if no data found from pricemaster check last similar order

def generate_instruction_filename(order_id, extension):
    # Assuming extension already includes the leading dot (e.g., '.pdf', '.jpg')
    unique_filename = f"UnloadingInstruction{order_id}_{uuid.uuid4().hex}{extension}"
    return unique_filename
#API to save unloading instruction pdfif user done any changes

# class SaveInstructionPDFView(APIView):
#     def post(self, request, *args, **kwargs):
#         order_id = request.data.get('order_id')
#         instruction_file = request.data.get('instruction_file')
#         if not order_id:
#             return Response({
#                 "status_code": 400,
#                 "status": "error",
#                 "message": "order_id is required"
#             }, status=status.HTTP_400_BAD_REQUEST)
#         if not instruction_file:
#             return Response({
#                 "status_code": 400,
#                 "status": "error",
#                 "message": "instruction_file is required"
#             }, status=status.HTTP_400_BAD_REQUEST)

#         saved_files = []
#         try:
#             # Get the base64 string directly (since instruction_file is a string)
#             file_content_base64 = instruction_file  # no .get()

#             if not file_content_base64:
#                 raise ValueError("No file data found in the request.")

#             # Check if the base64 string contains a MIME type (e.g., "data:image/png;base64,...")
#             if file_content_base64.startswith('data:'):
#                 # Extract MIME type and actual file data
#                 mime_type, file_content_base64 = file_content_base64.split(';base64,')
#             else:
#                 mime_type = None

#             # Decode the base64 content
#             file_content = base64.b64decode(file_content_base64)

#             # Determine the file extension based on MIME type
#             if mime_type:
#                 extension = MIME_TO_EXTENSION.get(mime_type, mimetypes.guess_extension(mime_type))
#                 if not extension:
#                     raise ValueError(f"Unsupported file type: {mime_type}")
#             else:
#                 extension = '.bin'

#             # Generate a unique file name with the correct extension
#             unique_file_name = generate_instruction_filename(order_id, extension)

#             # Create the directory if it doesn't exist
#             file_path = os.path.join(settings.DOCUMENTS_ROOT, unique_file_name)
#             os.makedirs(os.path.dirname(file_path), exist_ok=True)

#             # Save the file
#             with open(file_path, 'wb') as destination:
#                 destination.write(file_content)

#             # Insert a record into OrderRequestQuotation table
#             obj, created = OrderFiles.objects.update_or_create(
#                 OrderId=order_id,
#                 Type='UnloadingInstruction',
#                 defaults={'FileName': unique_file_name, 'IsDeleted': False}
#             )
#             saved_files.append(unique_file_name)
#             return Response(
#                 {
#                     "status": "success",
#                     "code": 200,
#                     "message": "File saved successfully",
#                     "saved_files": saved_files,
#                 },
#                 status=status.HTTP_200_OK,
#             )
#         except Exception as e:
#             return Response(
#                 {
#                     "status": "error",
#                     "code": 400,
#                     "message": f"Error saving file: {str(e)}",
#                 },
#                 status=status.HTTP_400_BAD_REQUEST,
#             )
# class ServeDocumentsView(APIView):
#     def get(self, request, filename):
#         # Construct the file path
#         file_path = os.path.join(settings.DOCUMENTS_ROOT,filename)
#         # Check if the file exists
#         if not os.path.exists(file_path):
#             return Response({
#                 "status_code": 404,
#                 "status": "error",
#                 "message": "File not found"
#             }, status=status.HTTP_404_NOT_FOUND)

#         try:
#             # Guess the content type of the file
#             content_type, _ = mimetypes.guess_type(file_path)
#             if content_type is None:
#                 content_type = 'application/octet-stream'  # fallback

#             # Serve the file
#             response = FileResponse(open(file_path, 'rb'), content_type=content_type)
#             response['Content-Disposition'] = f'inline; filename="{filename}"'
#             return response
#         except Exception as e:
#             return Response({
#                 "status_code": 500,
#                 "status": "error",
#                 "message": f"Error serving file: {str(e)}"
#             }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

class SaveUnloadingInstructionView(APIView):  # purchase order request creation/updation api
    def post(self, request, *args, **kwargs):
        # Extract data from the request body
        order_id = request.data.get('order_id')  # If present, this indicates an update
        article_code = request.data.get('article_code')
        inco_term = request.data.get('inco_term')
        load_point_id = request.data.get('load_point_id')
        ship_to_code = request.data.get('ship_to_code')
        bill_to_code = request.data.get('bill_to_code')
        instructions = request.data.get('instructions')
        if order_id is None or order_id == '' or instructions is None or instructions == '' or article_code is None or article_code == '' or inco_term is None or inco_term == '' or load_point_id is None or load_point_id == '' or ship_to_code is None or ship_to_code == '':
            return Response({
                "status_code": 400,
                "status": "error",
                "message": "order_id,article_code,inco_term,load_point_id,ship_to_code and instructions are required"
            }, status=status.HTTP_400_BAD_REQUEST)
        try:
            # delete all existing instruction with bill to filtering
            UnloadInstructions.objects.filter(
                ArticleCode=article_code,
                ExactERPAddressId=ship_to_code,
                BillTo=bill_to_code,
                IncoTerm=inco_term,
                LoadPointId=load_point_id,
                IsDeleted = 0
            ).update(IsDeleted=1)

            for item in instructions:
                UnloadInstructions.objects.create(
                    ArticleCode=article_code,
                    ExactERPAddressId=ship_to_code,
                    BillTo=bill_to_code,
                    IncoTerm=inco_term,
                    LoadPointId=load_point_id,
                    Instructions=item['text'],
                    Color=item['color'],
                    IsImageReq=item.get('is_image_req', 0),
                    IsDeleted=0,
                )
            return Response(
                {
                    "status": "success",
                    "code": 200,
                    "message": "Instructions saved successfully",
                },
                status=status.HTTP_200_OK,
            )
        except Exception as e:
            return Response(
                {
                    "status": "error",
                    "code": 400,
                    "message": f"Error processing request: {str(e)}",
                },
                status=status.HTTP_400_BAD_REQUEST,
            )


class DeleteOrderView(APIView):
    def post(self, request, *args, **kwargs):
        # Extract data from the request body
        order_id = request.data.get('order_id')  # If present, this indicates an update
        if order_id is None or order_id == '':
            return Response({
                "status_code": 400,
                "status": "error",
                "message": "order_id is required"
            }, status=status.HTTP_400_BAD_REQUEST)
        try:
            Orders.objects.filter(
              OrderNo=order_id
            ).update(IsDeleted=1)
            OrderRequests.objects.filter(
                Id=order_id
            ).update(IsDeleted=1)
            return Response(
                {
                    "status": "success",
                    "code": 200,
                    "message": "Deleted successfully",
                },
                status=status.HTTP_200_OK,
            )
        except Exception as e:
            return Response(
                {
                    "status": "error",
                    "code": 400,
                    "message": f"Error processing request: {str(e)}",
                },
                status=status.HTTP_400_BAD_REQUEST,
            )
class BodyPagination(PageNumberPagination):
    page_size = 10
    page_query_param = 'page'
    page_size_query_param = 'page_size'

    def get_page_number(self, request, paginator):
        return request.query_params.get(self.page_query_param, 1)

    def get_page_size(self, request):
        try:
            return int(request.data.get(self.page_size_query_param, self.page_size))
        except (TypeError, ValueError):
            return self.page_size
def get_filtered_queryset(queryset, search_string):
    q_filters = Q(
        Q(QuarterName__icontains=search_string) |
        Q(MinQuantity__icontains=search_string) |
        Q(ArticleCode__icontains=search_string) |
        Q(ExactERPAddressId__icontains=search_string) |
        Q(IncoTerm__icontains=search_string) |
        Q(OrderedByCustomer__icontains=search_string) |
        Q(ProductName__icontains=search_string) |
        Q(OfferRef__icontains=search_string) |
        Q(Price__icontains=search_string) |
        Q(PaymentTerm__icontains=search_string) |
        Q(DeliveryDestination__icontains=search_string) |
        Q(PriceConfirmation__icontains=search_string) |
        Q(Packaging__icontains=search_string) |
        Q(Remarks__icontains=search_string)
    )

    # Try full date: dd-mm-YYYY
    try:
        parsed_date = datetime.strptime(search_string, "%d-%m-%Y").date()
        q_filters |= Q(ValidityStartDate=parsed_date) | Q(ValidityEndDate=parsed_date)
    except ValueError:
        # Try partial date: dd-mm
        if re.match(r"^\d{2}-\d{2}$", search_string):
            day, month = search_string.split("-")
            q_filters |= Q(ValidityStartDate__day=day, ValidityStartDate__month=month)
            q_filters |= Q(ValidityEndDate__day=day, ValidityEndDate__month=month)
        else:
            # Fallback: date fields searched as strings (may still catch formatted strings if stored as text)
            q_filters |= Q(ValidityStartDate__icontains=search_string)
            q_filters |= Q(ValidityEndDate__icontains=search_string)

    return queryset.filter(q_filters)


class PriceListView(APIView):
    """fucntion to get and list prices in create pop up tab"""

    def post(self, request, *args, **kwargs):
        # Extract data from the request body
        outer_search = request.data.get('search_query')
        inner_search = request.data.get('search_string', None)
        order_id = request.data.get('order_id')
        package = request.data.get('package')
        sort_by = request.data.get('sort_by', 'valid_to')
        sort_order = request.data.get('sort_order', 'desc')
        page_number = request.data.get('page_number', 1)
        page_limit = request.data.get('page_limit', 20)


        if outer_search is None or outer_search == '':
            return Response({
                "status_code": 400,
                "status": "error",
                "message": "search_query is required"
            }, status=status.HTTP_400_BAD_REQUEST)
        payload = {
                "outer search": outer_search,
                "inner search": inner_search,
                "package_id": package, 
                "sort_by": sort_by,
                "sort_order": sort_order, 
                'page_no': page_number,
                'page_limit':page_limit
                }
        # try:
        client = OdooAPIService()
        response = client.get_price_list(params=payload)
        price_list = response['data']['price_list']

        price_list = purchase_utils.process_price_data(price_list)

        if response['status_code'] == 200:
            if order_id is not None:
                applied_row_id = OrderPriceLink.objects.filter(OrderId=order_id,IsDeleted=0).values_list('PriceRowId',flat=True).first() or ""
            else:
                applied_row_id = ''

            response_data = {
                'status_code': status.HTTP_200_OK,
                'status': 'success',
                'message': "Price list retrieved successfully.",
                'count': response['data']['total_count'],
                # 'next': paginated_response.data['next'],
                # 'previous': paginated_response.data['previous'],
                # 'data': paginated_response.data['results'],
                'data': response['data']['price_list'],
                'applied_row_id':applied_row_id
            }

            return Response(response_data, status=status.HTTP_200_OK)
        else:
            return Response({
                "status_code": 404,
                "status": "error",
                "message": "No matching address found"
            }, status=status.HTTP_404_NOT_FOUND)
                # else:
                #     return None
            # except requests.RequestException as e:
            #     return Response(
            #         {
            #             "status": "error",
            #             "code": 400,
            #             "message": f"Error processing request: {str(e)}",
            #         },
            #         status=status.HTTP_400_BAD_REQUEST,
                # )
        # except Exception as e:
        #     return Response(
        #         {
        #             "status": "error",
        #             "code": 400,
        #             "message": f"Error processing request: {str(e)}",
        #         },
        #         status=status.HTTP_400_BAD_REQUEST,
        #     )

class SaveOrderPriceView(APIView):
    def post(self, request, *args, **kwargs):
        # Extract data from the request body
        order_id = request.data.get('order_id')
        row_id = request.data.get('row_id')
        if order_id is None or order_id == '' or row_id is None or row_id == '':
            return Response({
                "status_code": 400,
                "status": "error",
                "message": "order_id and row_id are required"
            }, status=status.HTTP_400_BAD_REQUEST)
        try:
            existing_entry = OrderPriceLink.objects.filter(OrderId=order_id, IsDeleted=0).first()
            if existing_entry:
                existing_entry.PriceRowId = row_id
                existing_entry.save()
                message = "PriceRowId updated successfully"
            else:
                OrderPriceLink.objects.create(OrderId=order_id, PriceRowId=row_id)
                message = "New OrderPriceLink created successfully"

            return Response({
                "status_code": 200,
                "status": "success",
                "message": message
            }, status=status.HTTP_200_OK)

        except Exception as e:
            return Response({
                "status_code": 500,
                "status": "error",
                "message": str(e)
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

# Utility function to get similar orders
def get_similar_orders(order):
    base_filters = {
        'OrderedBy': order.OrderedBy,
        'ProductId': order.ProductId,
        'LoadPointId': order.LoadPointId,
        'IsDeleted': False,
        'IsOrder': True,
    }

    # Subquery to find valid linked orders
    valid_order_ids = Orders.objects.filter(
        OrderNo=OuterRef('Id'),
        StatusId__in=[2, 3, 4],
        IsDeleted=False
    ).values('OrderNo')

    filtered_queryset = OrderRequests.objects.annotate(
        has_valid_order=Subquery(valid_order_ids[:1])
    ).filter(has_valid_order__isnull=False)

    # Conditions with decreasing specificity
    conditions = []

    if all([order.DeliverTo, order.BillTo, order.Quantity, order.IncoTermsId]):
        conditions.append(Q(**base_filters,
                           DeliverTo=order.DeliverTo,
                           BillTo=order.BillTo,
                           Quantity=order.Quantity,
                           IncoTermsId=order.IncoTermsId))

    if all([order.DeliverTo, order.BillTo, order.Quantity]):
        conditions.append(Q(**base_filters,
                           DeliverTo=order.DeliverTo,
                           BillTo=order.BillTo,
                           Quantity=order.Quantity))

    if all([order.DeliverTo, order.BillTo]):
        conditions.append(Q(**base_filters,
                           DeliverTo=order.DeliverTo,
                           BillTo=order.BillTo))

    if order.DeliverTo:
        conditions.append(Q(**base_filters, DeliverTo=order.DeliverTo))

    # Always include base filter
    conditions.append(Q(**base_filters))

    # Collect all similar orders
    similar_orders = []
    for condition in conditions:
        try:
            matches = filtered_queryset.exclude(Id=order.Id).filter(condition).values(
                'Id', 'ExactOrderNo', 'DeliveryDate'
            ).order_by('-Id')
            if matches.exists():
                similar_orders.extend(list(matches))
        except Exception as e:
            continue  # Optionally log condition failure

    # Deduplicate by ID
    unique_orders = {
        o['Id']: {
            'Id': o['Id'],
            'OrderNo': o['ExactOrderNo'],
            'DeliveryDate': o['DeliveryDate'].strftime('%d.%m.%Y') if isinstance(o['DeliveryDate'], datetime) else o['DeliveryDate']
        } for o in similar_orders
    }

    return list(unique_orders.values())


class SimilarOrderView(APIView):
    def post(self, request, *args, **kwargs):
        serializer = SimilarOrderInputSerializer(data=request.data)
        if not serializer.is_valid():
            return Response({
                "status_code": 400,
                "status": "failed",
                "message": "Validation failed",
                "error": serializer.errors,
                "data": None
            }, status=status.HTTP_400_BAD_REQUEST)

        order_id = serializer.validated_data['order_id']

        try:
            order = OrderRequests.objects.get(Id=order_id, IsDeleted=False)
        except OrderRequests.DoesNotExist:
            return Response({
                "status_code": 404,
                "status": "failed",
                "message": "Order not found",
                "error": "The order with the provided ID does not exist",
                "data": None
            }, status=status.HTTP_404_NOT_FOUND)

        try:
            unique_orders = get_similar_orders(order)

            # Determine if the current order is confirmed
            order_record = Orders.objects.filter(OrderNo=order_id, IsDeleted=False).first()
            is_order = 1 if order_record and order_record.StatusId != 1 else 0

            response_data = {
                "unique_orders": unique_orders,
                "is_order": is_order
            }

            return Response({
                "status_code": 200,
                "status": "success",
                "message": "Order details fetched successfully.",
                "data": response_data,
            }, status=status.HTTP_200_OK)

        except Exception as e:
            import traceback
            return Response({
                "status_code": 500,
                "status": "failed",
                "message": "An error occurred",
                "error": str(e),
                "trace": traceback.format_exc(),
                "data": None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)



class ExtraChargeListView(APIView):
    
    def post(self, request):
        """
        Fetch extra charges applied to an order request.
        - is_planned=True  → show only already-selected order charges (no day/date recalculation).
        - is_planned=False → recalculate day-based special charges and sample transport.
        Date/quantity changes from the original order always force is_planned=False.
        """     
        data = request.data

        order_request_id = data.get('order_request_id')
        delivery_date = data.get('delivery_date')
        loading_date = data.get('loading_date')
        quantity = data.get('quantity')
        is_sample_required = data.get('is_sample_required')
        is_planned = data.get('is_planned')

        try:
            order_request = OrderRequests.objects.get(Id=order_request_id)
            order = Orders.objects.filter(OrderNo=order_request_id, IsDeleted=False).first()
        except:
            return Response({
                "status_code": 404,
                "status": "error",
                "message": "Order request not found",
                "error": "The order request with the provided ID does not exist",
                "data": None
            }, status=status.HTTP_404_NOT_FOUND)

        # convert to date obj
        delivery_date = datetime.strptime(delivery_date, '%Y-%m-%d').date() if delivery_date else None
        loading_date = datetime.strptime(loading_date, '%Y-%m-%d').date() if loading_date else None

        actual_delivery_date = order_request.DeliveryDate
        actual_loading_date = order_request.LoadingDate
        loading_day = loading_date.strftime("%A")
        delivery_day = delivery_date.strftime("%A") if delivery_date else None
        date_changed=False

        actual_sample_required = True if order and order.NeedSample=='YES' else False

        # check if date has changed from actual date
        if delivery_date != actual_delivery_date or loading_date != actual_loading_date:
            date_changed=True
            is_planned=False
        
        if is_sample_required != actual_sample_required:
            sample_changed=True
        else:
            sample_changed=False 

        special_charge_name = [
                "Delivery on Saturday - Loading on Friday",
                "Delivery on Saturday - Loading on Saturday",
                "Delivery on Sunday /bank holiday - Loading on Friday",
                "Delivery on Sunday/bank holiday - Loading on Saturday",
                "Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday"
            ]

        if is_planned:
            special_charge = None
        else:
            # delete all order charges related to day
            OrderCharges.objects.filter(
                OrderNo=order_request_id, IsDeleted=False, ChargeName__in=special_charge_name).update(IsDeleted=True)
            
            if loading_day and delivery_day and loading_day == "Friday" and delivery_day == "Saturday":
                special_charge = ExtraCharges.objects.filter(
                    IsDeleted=False, Name="Delivery on Saturday - Loading on Friday")
            elif loading_day and delivery_day and loading_day == "Saturday" and delivery_day == "Saturday":
                special_charge = ExtraCharges.objects.filter(
                    IsDeleted=False, Name="Delivery on Saturday - Loading on Saturday")
            elif loading_day and delivery_day and loading_day == "Friday" and delivery_day == "Sunday":
                special_charge = ExtraCharges.objects.filter(
                    IsDeleted=False, Name="Delivery on Sunday /bank holiday - Loading on Friday")
            elif loading_day and delivery_day and loading_day == "Saturday" and delivery_day == "Sunday":
                special_charge = ExtraCharges.objects.filter(
                    IsDeleted=False, Name="Delivery on Sunday/bank holiday - Loading on Saturday")
            elif loading_day and delivery_day and loading_day == "Sunday" and delivery_day == "Sunday":
                special_charge = ExtraCharges.objects.filter(
                    IsDeleted=False, Name="Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday")
            else:
                special_charge = None

        # get all applied order charges
        existing_charges = OrderCharges.objects.filter(OrderNo=order_request_id, IsDeleted=False)

        # get all extra charges (applied and not applied)
        extra_charges = ExtraCharges.objects.filter(IsDeleted=False).annotate(
                    ChargeName=F('Name'),
                    Rate=F('Amount'),
                    IsApplied=Value(False),
                    ExtraChargeId=F('Id'),
                ).values('ChargeName', 'Rate', 'IsApplied', 'ExtraChargeId', 'ArticleCode', 'OrderIndex' )

        extra_charges = list(extra_charges)

        if special_charge:
            resolved = special_charge.first()
            for charge in extra_charges:
                if charge['ChargeName'] == resolved.Name:
                    charge['IsApplied']     = True
                    charge['Rate']          = resolved.Amount
                    charge['ExtraChargeId'] = resolved.Id
                    charge['ArticleCode']   = resolved.ArticleCode

                    OrderCharges.objects.create(
                        OrderNo=order_request_id,
                        ChargeName=resolved.Name,
                        Rate=resolved.Amount,
                        ExtraChargeId=resolved.Id,
                        ArticleCode=resolved.ArticleCode,
                        IsDeleted=False,
                    )
                    break
            # elif existing_charges:
            #     charge['IsApplied'] = True
            #     charge['Rate'] = existing_charges.first().Amount
            #     charge['ExtraChargeId'] = existing_charges.first().Id
            #     charge['ArticleCode'] = existing_charges.first().ArticleCode

        total_price = 0
        applied_charges_count = 0

        # for existing charges , find charge from extra carges  make is applied=true and add in extra charges list
        for order_charge in existing_charges:
            for extra_charge in extra_charges:
                if order_charge.ChargeName == extra_charge['ChargeName']:
                    extra_charge['IsApplied'] = True
                    total_price += float(extra_charge['Rate'])
                    applied_charges_count += 1
                    break
            else:
                # only runs if the inner loop never hit `break` (no match found)
                if order_charge.ExtraChargeId is None:
                    extra_charges.append({
                        'ChargeName':    order_charge.ChargeName,
                        'Rate':          order_charge.Rate,
                        'ExtraChargeId': None,
                        'ArticleCode':   order_charge.ArticleCode,
                        'IsApplied':     True,
                        'OrderIndex':    None,
                    })
                    total_price += float(order_charge.Rate)
                    applied_charges_count += 1

        if not is_planned:
            if is_sample_required:
                try:
                    sample_charge = OrderCharges.objects.get(
                                OrderNo=order_request_id, IsDeleted=False, ChargeName="Sample Transport")
                except OrderCharges.DoesNotExist:
                    for extra_charge in extra_charges:
                        if extra_charge['ChargeName'] == "Sample Transport":
                            extra_charge['IsApplied'] = True
                            OrderCharges.objects.create(
                                            OrderNo=order_request_id,
                                            ExtraChargeId=extra_charge['ExtraChargeId'],
                                            ChargeName=extra_charge['ChargeName'],
                                            Rate=extra_charge['Rate'],
                                            ArticleCode=extra_charge['ArticleCode'])

                            total_price = total_price + float(extra_charge['Rate'])
                            applied_charges_count = applied_charges_count + 1
                
            else:
                try:
                    sample_charge = OrderCharges.objects.get(
                                OrderNo=order_request_id, IsDeleted=False, ChargeName="Sample Transport")
                    if sample_charge:
                        for extra_charge in extra_charges:
                            if extra_charge['ChargeName'] == "Sample Transport":
                                extra_charge['IsApplied'] = False
                                sample_charge.IsDeleted = True
                                sample_charge.save()

                                total_price = total_price - float(extra_charge['Rate'])
                                applied_charges_count = applied_charges_count - 1
                except OrderCharges.DoesNotExist:
                    pass

        # if sample_changed:
        #     OrderCharges.objects.filter(
        #                 OrderNo=order_request_id, IsDeleted=False, ChargeName="Sample Transport").update(
        #                     IsDeleted=True)
        #     if is_sample_required:
                
        #         for extra_charge in extra_charges:
        #             if extra_charge['ChargeName'] == "Sample Transport":
        #                 extra_charge['IsApplied'] = True
        #                 OrderCharges.objects.create(
        #                                 OrderNo=order_request_id,
        #                                 ExtraChargeId=extra_charge['ExtraChargeId'],
        #                                 ChargeName=extra_charge['ChargeName'],
        #                                 Rate=extra_charge['Rate'],
        #                                 ArticleCode=extra_charge['ArticleCode'])

        #                 total_price = total_price + float(extra_charge['Rate'])
        #                 applied_charges_count = applied_charges_count + 1


        data = {
            "order_charges": extra_charges, 
            "count":applied_charges_count,
            "formatted_extra_charge": "None", 
            "total_extra_charge": total_price,
        }
            
        

        return Response({
            "status_code": 200,
            "status": "success",
            "message": "Extra charge details fetched successfully.",
            "data": data,
        }, status=status.HTTP_200_OK)
            


# class ExtraChargeListView(APIView):
#     def post(self, request):
#         required_fields = [
#             "order_request_id", "loading_date", "quantity"
#         ]
#         data = request.data
#         # Iterate through each field and check if it's null or empty
#         for field in required_fields:
#             value = data.get(field)
#             # If any required field is missing or empty
#             if value is None or (isinstance(value, str) and value.strip() == ''):
#                 # Return error response and stop the process
#                 return Response({
#                     "status_code": 400,
#                     "status": "error",
#                     "message": f"The field '{field}' is required and cannot be null or empty."
#                 }, status=status.HTTP_400_BAD_REQUEST)
#         order_request_id = request.data.get('order_request_id')
#         delivery_date = request.data.get('delivery_date')
#         loading_date = request.data.get('loading_date')
#         quantity = request.data.get('quantity')
#         is_sample_required = request.data.get('is_sample_required')

#         order_request = OrderRequests.objects.get(Id=order_request_id)
#         ordered_customer_id = order_request.OrderedBy
#         ordered_customer = get_address_with_id(request.headers.get('x-auth-token'), ordered_customer_id)

#         is_customer_exxon = True if 'exxon' in ordered_customer['CustomerName'].lower() else False

#         # order_charges_set = list(OrderCharges.objects.filter(OrderNo=order_request_id, IsDeleted=False)
#         #                    .annotate(
#         #     IsApplied=Value(True),
#         #     amount=F('Rate')
#         # ).values('ChargeName', 'amount', 'IsApplied', 'ExtraChargeId'))

#         order_charges_set = list(OrderCharges.objects.filter(OrderNo=order_request_id, IsDeleted=False)
#                              .exclude(
#             ChargeName__in=["Delivery on Saturday - Loading on Friday",
#                             "Delivery on Saturday - Loading on Saturday",
#                             "Delivery on Sunday /bank holiday - Loading on Friday",
#                             "Delivery on Sunday/bank holiday - Loading on Saturday",
#                             "Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday"]
#         ))

#         order_charges = []
#         for oc in order_charges_set:
#             is_applied = True
#             order_charges.append({
#                 "ChargeName": oc.ChargeName,
#                 "Rate": oc.Rate,
#                 "IsApplied": is_applied,
#                 "ExtraChargeId": oc.ExtraChargeId,
#                 "IsExxon": oc.get_is_exxon if oc.get_is_exxon else 0,
#                 "ArticleCode": oc.get_charge_article_code
#             })

#         if order_charges: #if already applied charges exist fetch that charges and remove Exxon Group, Rotterdam extra charges from that list,then append remaining non-applied charges

#             extra_charges = ExtraCharges.objects.filter(IsDeleted=False)
#             serializer = ExtraChargeSerializer(extra_charges, many=True)
#             if serializer.data:
#                 quantity_surcharge_exists = 0
#                 for extra_charge in serializer.data:
#                     # Check if an existing charge has a name similar to "surcharge for deliveries"
#                     similar_charge_exists = OrderCharges.objects.filter(
#                         OrderNo=order_request_id,
#                         IsDeleted=False,
#                         ChargeName__icontains="specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%"
#                     ).exists()
#                     if similar_charge_exists:
#                         quantity_surcharge_exists = 1
#                         OrderCharges.objects.filter(
#                             OrderNo=order_request_id,
#                             IsDeleted=False,
#                             ChargeName__icontains="specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%"
#                         ).update(IsDeleted=True) #remove the exxon charge
#                         order_charges = list(OrderCharges.objects.filter(OrderNo=order_request_id, IsDeleted=False)
#                                              .exclude(
#                             ChargeName__in=["Delivery on Saturday - Loading on Friday",
#                                             "Delivery on Saturday - Loading on Saturday",
#                                             "Delivery on Sunday /bank holiday - Loading on Friday",
#                                             "Delivery on Sunday/bank holiday - Loading on Saturday",
#                                             "Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday"]
#                         ).annotate(
#                             IsApplied=Value(True)
#                         ).values('ChargeName', 'Rate', 'IsApplied', 'ExtraChargeId', 'ArticleCode'))
#                     # existing_charge_names = {charge['ChargeName'] for charge in order_charges}
#                     existing_charge_ids = {charge['ExtraChargeId'] for charge in order_charges}
#                     if extra_charge['Id'] not in existing_charge_ids: #append all other charges from the list
#                         order_charges.append({
#                             'ChargeName': extra_charge['Name'],
#                             'Rate': extra_charge['Amount'],
#                             'IsApplied': False,
#                             'ExtraChargeId': extra_charge['Id'],
#                             'IsExxon': extra_charge['IsExxon'],
#                             'ArticleCode': extra_charge['ArticleCode']
#                         })


#         else: #fetch all extra charges
#             order_charges = list( #fetch all extra charges
#                 ExtraCharges.objects.filter(IsDeleted=False)
#                 .annotate(
#                     ChargeName=F('Name'),
#                     Rate=F('Amount'),
#                     IsApplied=Value(False),
#                     ExtraChargeId=F('Id'),
#                 )
#                 .values('ChargeName', 'Rate', 'IsApplied', 'ExtraChargeId', 'IsExxon', 'ArticleCode')
#             )

#             quantity_surcharge_exists = 0
#         # If rows with the holiday charge  exist then remove that
#         order_charges_to_delete = OrderCharges.objects.filter(
#             OrderNo=order_request_id,
#             IsDeleted=False,
#             ChargeName__icontains="Delivery on Saturday - Loading on Friday"
#         ) | OrderCharges.objects.filter(
#             OrderNo=order_request_id,
#             IsDeleted=False,
#             ChargeName__icontains="Delivery on Saturday - Loading on Saturday"
#         ) | OrderCharges.objects.filter(
#             OrderNo=order_request_id,
#             IsDeleted=False,
#             ChargeName__icontains="Delivery on Sunday /bank holiday - Loading on Friday"
#         ) | OrderCharges.objects.filter(
#             OrderNo=order_request_id,
#             IsDeleted=False,
#             ChargeName__icontains="Delivery on Sunday/bank holiday - Loading on Saturday"
#         ) | OrderCharges.objects.filter(
#             OrderNo=order_request_id,
#             IsDeleted=False,
#             ChargeName__icontains="Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday"
#         ) | OrderCharges.objects.filter(
#             OrderNo=order_request_id,
#             IsDeleted=False,
#             ChargeName__icontains="Sample Transport"
#         ) 
#         cc = OrderCharges.objects.filter(
#             OrderNo=order_request_id,
#             IsDeleted=False,
#             ChargeName__icontains="Sample Transport"
#         ) 
#         # If such rows exist, update their IsDeleted status to True
#         if order_charges_to_delete.exists():
#             order_charges_to_delete.update(IsDeleted=True)

#         if delivery_date and delivery_date!='':
#             date_obj1 = datetime.strptime(delivery_date, '%Y-%m-%d')
#             day_index1 = date_obj1.weekday()
#             delivery_day = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'][day_index1]
#             date_obj2 = datetime.strptime(loading_date, '%Y-%m-%d')
#             day_index2 = date_obj2.weekday()
#             loading_day = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'][day_index2]
#             if delivery_day == 'Saturday' and loading_day == 'Friday':
#                 for charge in order_charges:
#                     if is_customer_exxon and charge.get('IsExxon') == 1 and charge.get('ChargeName') == "Delivery on Saturday - Loading on Friday":
#                         charge['IsApplied'] = True
#                         OrderCharges.objects.create(
#                             OrderNo=order_request_id,
#                             ExtraChargeId=charge.get('ExtraChargeId'),
#                             ChargeName="Delivery on Saturday - Loading on Friday",
#                             Rate=charge['Rate'],
#                             ArticleCode=charge.get('ArticleCode')

#                         )
#                         break
#                     elif not is_customer_exxon and charge.get('IsExxon') == 0 and charge.get('ChargeName') == "Delivery on Saturday - Loading on Friday":
#                         charge['IsApplied'] = True
#                         is_exxon = 0
#                         OrderCharges.objects.create(
#                             OrderNo=order_request_id,
#                             ExtraChargeId=charge.get('ExtraChargeId'),
#                             ChargeName="Delivery on Saturday - Loading on Friday",
#                             Rate=charge['Rate'],  
#                             ArticleCode=charge.get('ArticleCode')
#                         )
#                         break

#             elif delivery_day == 'Saturday' and loading_day == 'Saturday':
#                 for charge in order_charges:
#                     # if charge.get('ChargeName') == "Delivery on Saturday - Loading on Saturday":
#                     #     charge['IsApplied'] = True
#                     #     break
#                 # OrderCharges.objects.create(
#                 #     OrderNo=order_request_id,
#                 #     ChargeName="Delivery on Saturday - Loading on Saturday",
#                 #     Rate=955,
#                 # )

#                     if is_customer_exxon and charge.get('IsExxon') == 1 and charge.get(
#                             'ChargeName') == "Delivery on Saturday - Loading on Saturday":
#                         charge['IsApplied'] = True
#                         is_exxon = 1
#                         OrderCharges.objects.create(
#                             OrderNo=order_request_id,
#                             ExtraChargeId=charge.get('ExtraChargeId'),
#                             ChargeName="Delivery on Saturday - Loading on Saturday",
#                             Rate=charge['Rate'],
#                             ArticleCode=charge.get('ArticleCode')
#                         )
#                         break
#                     elif not is_customer_exxon and charge.get('IsExxon') == 0 and charge.get(
#                             'ChargeName') == "Delivery on Saturday - Loading on Saturday":
#                         charge['IsApplied'] = True
#                         is_exxon = 0
#                         OrderCharges.objects.create(
#                             OrderNo=order_request_id,
#                             ExtraChargeId=charge.get('ExtraChargeId'),
#                             ChargeName="Delivery on Saturday - Loading on Saturday",
#                             Rate=charge['Rate'],
#                             ArticleCode=charge.get('ArticleCode')
#                         )
#                         break


#             elif delivery_day == 'Sunday' and loading_day == 'Friday':
#                 for charge in order_charges:
#                 #     if charge.get('ChargeName') == "Delivery on Sunday /bank holiday - Loading on Friday":
#                 #         charge['IsApplied'] = True
#                 #         break
#                 # OrderCharges.objects.create(
#                 #     OrderNo=order_request_id,
#                 #     ChargeName="Delivery on Sunday /bank holiday - Loading on Friday",
#                 #     Rate=580,
#                 # )

#                     if is_customer_exxon and charge.get('IsExxon') == 1 and charge.get(
#                             'ChargeName') == "Delivery on Sunday /bank holiday - Loading on Friday":
#                         charge['IsApplied'] = True
#                         is_exxon = 1
#                         OrderCharges.objects.create(
#                             OrderNo=order_request_id,
#                             ExtraChargeId=charge.get('ExtraChargeId'),
#                             ChargeName="Delivery on Sunday /bank holiday - Loading on Friday",
#                             Rate=charge['Rate'],
#                             ArticleCode=charge.get('ArticleCode')
#                         )
#                         break
#                     elif not is_customer_exxon and charge.get('IsExxon') == 0 and charge.get(
#                             'ChargeName') == "Delivery on Sunday /bank holiday - Loading on Friday":
#                         charge['IsApplied'] = True
#                         is_exxon = 0
#                         OrderCharges.objects.create(
#                             OrderNo=order_request_id,
#                             ExtraChargeId=charge.get('ExtraChargeId'),
#                             ChargeName="Delivery on Sunday /bank holiday - Loading on Friday",
#                             Rate=charge['Rate'],
#                             ArticleCode=charge.get('ArticleCode')
#                         )
#                         break

#             elif delivery_day == 'Sunday' and loading_day == 'Saturday':
#                 for charge in order_charges:
#                 #     if charge.get('ChargeName') == "Delivery on Sunday/bank holiday - Loading on Saturday":
#                 #         charge['IsApplied'] = True
#                 #         break
#                 # OrderCharges.objects.create(
#                 #     OrderNo=order_request_id,
#                 #     ChargeName="Delivery on Sunday/bank holiday - Loading on Saturday",
#                 #     Rate=955,
#                 # )
#                     if is_customer_exxon and charge.get('IsExxon') == 1 and charge.get(
#                             'ChargeName') == "Delivery on Sunday/bank holiday - Loading on Saturday":
#                         charge['IsApplied'] = True
#                         is_exxon = 1
#                         OrderCharges.objects.create(
#                             OrderNo=order_request_id,
#                             ExtraChargeId=charge.get('ExtraChargeId'),
#                             ChargeName="Delivery on Sunday/bank holiday - Loading on Saturday",
#                             Rate=charge['Rate'],
#                             ArticleCode=charge.get('ArticleCode')
#                         )
#                         break
#                     elif not is_customer_exxon and charge.get('IsExxon') == 0 and charge.get(
#                             'ChargeName') == "Delivery on Sunday/bank holiday - Loading on Saturday":
#                         charge['IsApplied'] = True
#                         is_exxon = 0
#                         OrderCharges.objects.create(
#                             OrderNo=order_request_id,
#                             ExtraChargeId=charge.get('ExtraChargeId'),
#                             ChargeName="Delivery on Sunday/bank holiday - Loading on Saturday",
#                             Rate=charge['Rate'],
#                             ArticleCode=charge.get('ArticleCode')
#                         )
#                         break
#             elif delivery_day == 'Sunday' and loading_day == 'Sunday':
#                 for charge in order_charges:
#                 #     if charge.get('ChargeName') == "Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday":
#                 #         charge['IsApplied'] = True
#                 #         break
#                 # OrderCharges.objects.create(
#                 #     OrderNo=order_request_id,
#                 #     ChargeName="Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday",
#                 #     Rate=1070,
#                 # )
#                     if is_customer_exxon and charge.get('IsExxon') == 1 and charge.get(
#                             'ChargeName') == "Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday":
#                         charge['IsApplied'] = True
#                         is_exxon = 1
#                         OrderCharges.objects.create(
#                             OrderNo=order_request_id,
#                             ExtraChargeId=charge.get('ExtraChargeId'),
#                             ChargeName="Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday",
#                             Rate=charge['Rate'],
#                             ArticleCode=charge.get('ArticleCode')
#                         )
#                         break
#                     elif not is_customer_exxon and charge.get('IsExxon') == 0 and charge.get(
#                             'ChargeName') == "Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday":
#                         charge['IsApplied'] = True
#                         is_exxon = 0
#                         OrderCharges.objects.create(
#                             OrderNo=order_request_id,
#                             ExtraChargeId=charge.get('ExtraChargeId'),
#                             ChargeName="Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday",
#                             Rate=charge['Rate'],
#                             ArticleCode=charge.get('ArticleCode')
#                         )
#                         break
#             else:  # check delivery day a bank holiday
#                 if OffDays.objects.filter(Date=delivery_date, IsDeleted=False).exists():
#                     if loading_day == 'Friday':
#                         for charge in order_charges:
#                         #     if charge.get('ChargeName') == "Delivery on Sunday /bank holiday - Loading on Friday":
#                         #         charge['IsApplied'] = True
#                         #         break
#                         # OrderCharges.objects.create(
#                         #     OrderNo=order_request_id,
#                         #     ChargeName="Delivery on Sunday /bank holiday - Loading on Friday",
#                         #     Rate=580,
#                         # )
#                             if is_customer_exxon and charge.get('IsExxon') == 1 and charge.get(
#                                     'ChargeName') == "Delivery on Sunday /bank holiday - Loading on Friday":
#                                 charge['IsApplied'] = True
#                                 is_exxon = 1
#                                 OrderCharges.objects.create(
#                                     OrderNo=order_request_id,
#                                     ExtraChargeId=charge.get('ExtraChargeId'),
#                                     ChargeName="Delivery on Sunday /bank holiday - Loading on Friday",
#                                     Rate=charge['Rate'],
#                                     ArticleCode=charge.get('ArticleCode')
#                                 )
#                                 break
#                             elif not is_customer_exxon and charge.get('IsExxon') == 0 and charge.get(
#                                     'ChargeName') == "Delivery on Sunday /bank holiday - Loading on Friday":
#                                 charge['IsApplied'] = True
#                                 is_exxon = 0
#                                 OrderCharges.objects.create(
#                                     OrderNo=order_request_id,
#                                     ExtraChargeId=charge.get('ExtraChargeId'),
#                                     ChargeName="Delivery on Sunday /bank holiday - Loading on Friday",
#                                     Rate=charge['Rate'],
#                                     ArticleCode=charge.get('ArticleCode')
#                                 )
#                                 break
#                     elif loading_day == 'Saturday':
#                         for charge in order_charges:
#                         #     if charge.get('ChargeName') == "Delivery on Sunday/bank holiday - Loading on Saturday":
#                         #         charge['IsApplied'] = True
#                         #         break
#                         # OrderCharges.objects.create(
#                         #     OrderNo=order_request_id,
#                         #     ChargeName="Delivery on Sunday/bank holiday - Loading on Saturday",
#                         #     Rate=955,
#                         # )
#                             if is_customer_exxon and charge.get('IsExxon') == 1 and charge.get(
#                                     'ChargeName') == "Delivery on Sunday/bank holiday - Loading on Saturday":
#                                 charge['IsApplied'] = True
#                                 is_exxon = 1
#                                 OrderCharges.objects.create(
#                                     OrderNo=order_request_id,
#                                     ExtraChargeId=charge.get('ExtraChargeId'),
#                                     ChargeName="Delivery on Sunday/bank holiday - Loading on Saturday",
#                                     Rate=charge['Rate'],
#                                 )
#                                 break
#                             elif not is_customer_exxon and charge.get('IsExxon') == 0 and charge.get(
#                                     'ChargeName') == "Delivery on Sunday/bank holiday - Loading on Saturday":
#                                 charge['IsApplied'] = True
#                                 is_exxon = 0
#                                 OrderCharges.objects.create(
#                                     OrderNo=order_request_id,
#                                     ExtraChargeId=charge.get('ExtraChargeId'),
#                                     ChargeName="Delivery on Sunday/bank holiday - Loading on Saturday",
#                                     Rate=charge['Rate'],
#                                     ArticleCode=charge.get('ArticleCode')
#                                 )
#                                 break
#                     elif loading_day == 'Sunday':
#                         for charge in order_charges:
#                         #     if charge.get('ChargeName') == "Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday":
#                         #         charge['IsApplied'] = True
#                         #         break
#                         # OrderCharges.objects.create(
#                         #     OrderNo=order_request_id,
#                         #     ChargeName="Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday",
#                         #     Rate=1070,
#                         # )
#                             if is_customer_exxon and charge.get('IsExxon') == 1 and charge.get(
#                                     'ChargeName') == "Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday":
#                                 charge['IsApplied'] = True
#                                 is_exxon = 1
#                                 OrderCharges.objects.create(
#                                     OrderNo=order_request_id,
#                                     ExtraChargeId=charge.get('ExtraChargeId'),
#                                     ChargeName="Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday",
#                                     Rate=charge['Rate'],
#                                     ArticleCode=charge.get('ArticleCode')
#                                 )
#                                 break
#                             elif not is_customer_exxon and charge.get('IsExxon') == 0 and charge.get(
#                                     'ChargeName') == "Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday":
#                                 charge['IsApplied'] = True
#                                 is_exxon = 0
#                                 OrderCharges.objects.create(
#                                     OrderNo=order_request_id,
#                                     ExtraChargeId=charge.get('ExtraChargeId'),
#                                     ChargeName="Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday",
#                                     Rate=charge['Rate'],
#                                     ArticleCode=charge.get('ArticleCode')
#                                 )
#                                 break
#                     elif OffDays.objects.filter(Date=loading_date, IsDeleted=False).exists():
#                         for charge in order_charges:
#                         #     if charge.get(
#                         #             'ChargeName') == "Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday":
#                         #         charge['IsApplied'] = True
#                         #         break
#                         # OrderCharges.objects.create(
#                         #     OrderNo=order_request_id,
#                         #     ChargeName="Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday",
#                         #     Rate=1070,
#                         # )
#                             if is_customer_exxon and charge.get('IsExxon') == 1 and charge.get(
#                                     'ChargeName') == "Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday":
#                                 charge['IsApplied'] = True
#                                 is_exxon = 1
#                                 OrderCharges.objects.create(
#                                     OrderNo=order_request_id,
#                                     ExtraChargeId=charge.get('ExtraChargeId'),
#                                     ChargeName="Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday",
#                                     Rate=charge['Rate'],
#                                     ArticleCode=charge.get('ArticleCode')
#                                 )
#                                 break
#                             elif not is_customer_exxon and charge.get('IsExxon') == 0 and charge.get(
#                                     'ChargeName') == "Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday":
#                                 charge['IsApplied'] = True
#                                 is_exxon = 0
#                                 OrderCharges.objects.create(
#                                     OrderNo=order_request_id,
#                                     ExtraChargeId=charge.get('ExtraChargeId'),
#                                     ChargeName="Delivery on Sunday/bank holiday - Loading on Sunday/bank holiday",
#                                     Rate=charge['Rate'],
#                                     ArticleCode=charge.get('ArticleCode')
#                                 )
#                                 break
#         for charge in order_charges:
#             if charge.get(
#                     'ChargeName') == "€13/MT surcharge for deliveries of 20-25MT, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)":
#                 charge['Rate'] = str(quantity * 13)
#             elif charge.get(
#                     'ChargeName') == "€30/MT surcharge for deliveries of 15-20MT, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)":
#                 charge['Rate'] = str(quantity * 30)
#             elif charge.get(
#                     'ChargeName') == "€55/MT surcharge for deliveries of 10-15MT, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)":
#                 charge['Rate'] = str(quantity * 55)
#             elif charge.get(
#                     'ChargeName') == "€283/MT surcharge for deliveries of 5MT or less, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)":
#                 charge['Rate'] = str(quantity * 283)
#             if is_sample_required and charge.get('ChargeName') == "Sample Transport":
#                 charge['IsApplied'] = True
#                 OrderCharges.objects.create(
#                                 OrderNo=order_request_id,
#                                 ExtraChargeId=charge.get('ExtraChargeId'),
#                                 ChargeName=charge.get('ChargeName'),
#                                 Rate=charge.get('Rate'),
#                                 ArticleCode=charge.get('ArticleCode')

#                             )
#         if quantity < 25:
#             if quantity_surcharge_exists == 1:
#                 if 20 <= quantity < 25:
#                     for charge in order_charges:
#                         if charge.get('ChargeName') == "€13/MT surcharge for deliveries of 20-25MT, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)":
#                             charge['IsApplied'] = True
#                             break
#                     extra_charge = ExtraCharges.objects.filter(Name="€13/MT surcharge for deliveries of 20-25MT, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)").first()
#                     OrderCharges.objects.create(
#                         OrderNo=order_request_id,
#                         ChargeName="€13/MT surcharge for deliveries of 20-25MT, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)",
#                         Rate=quantity * 13,
#                         ExtraChargeId=extra_charge.Id,
#                         ArticleCode=charge.get('ArticleCode')

#                     )
#                 elif 15 <= quantity < 20:
#                     for charge in order_charges:
#                         if charge.get('ChargeName') == "€30/MT surcharge for deliveries of 15-20MT, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)":
#                             charge['IsApplied'] = True
#                             break
#                     extra_charge = ExtraCharges.objects.filter(
#                         Name="€30/MT surcharge for deliveries of 15-20MT, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)").first()
#                     OrderCharges.objects.create(
#                         OrderNo=order_request_id,
#                         ChargeName="€30/MT surcharge for deliveries of 15-20MT, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)",
#                         Rate=quantity * 30,
#                         ExtraChargeId=extra_charge.Id,
#                         ArticleCode=charge.get('ArticleCode')
#                     )
#                 elif 10 <= quantity < 15:
#                     for charge in order_charges:
#                         if charge.get('ChargeName') == "€55/MT surcharge for deliveries of 10-15MT, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)":
#                             charge['IsApplied'] = True
#                             break
#                     extra_charge = ExtraCharges.objects.filter(
#                         Name="€55/MT surcharge for deliveries of 10-15MT, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)").first()
#                     OrderCharges.objects.create(
#                         OrderNo=order_request_id,
#                         ChargeName="€55/MT surcharge for deliveries of 10-15MT, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)",
#                         Rate=quantity * 55,
#                         ExtraChargeId=extra_charge.Id,
#                         ArticleCode=charge.get('ArticleCode')
#                     )
#                 elif quantity <= 5:
#                     for charge in order_charges:
#                         if charge.get('ChargeName') == "€283/MT surcharge for deliveries of 5MT or less, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)":
#                             charge['IsApplied'] = True
#                             break
#                     extra_charge = ExtraCharges.objects.filter(
#                         Name="€283/MT surcharge for deliveries of 5MT or less, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)").first()
#                     OrderCharges.objects.create(
#                         OrderNo=order_request_id,
#                         ChargeName="€283/MT surcharge for deliveries of 5MT or less, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)",
#                         Rate=quantity * 283,
#                         ExtraChargeId=extra_charge.Id,
#                         ArticleCode=charge.get('ArticleCode')
#                     )
#         total_charges = OrderCharges.objects.filter(OrderNo=order_request_id, IsDeleted=False).aggregate(
#             total_amount=Sum('Rate'),
#             charge_count=Count('Rate')
#         )
#         return Response(
#             {
#                 "status_code": 200,
#                 "status": "success",
#                 "message": "Extra charge details fetched successfully.",
#                 "data": {
#                     "order_charges": order_charges,
#                     "total_extra_charge": total_charges['total_amount'],
#                     "count": total_charges['charge_count'],
#                     "formatted_extra_charge": convert_to_belgium_format(total_charges['total_amount'])
#                 }
#             },
#             status=status.HTTP_200_OK
#         )

class SyncPriceMasterView(APIView):
    def post(self, request, *args, **kwargs):
        """function to sync price data from google sheet"""

        sheet_name = request.data.get('sheet')
        add_data = request.data.get('add_data')
        year = request.data.get('year', 2025)
        check_ship_to = request.data.get('check_ship_to')
        if not sheet_name:
            raise ValidationError({
                "status_code": 400,
                "status": "error",
                "message": f"sheet name required (Q3, Q2, transport)",
                "data": None
            })

        add_list, skip_list, remove_list = update_price_master_from_sheet.update_price_from_sheet(
            sheet_name, year,  add_data,  check_ship_to=True)

        return Response(
                {
                    "status_code": 200,
                    "status": "success",
                    "message": "Datas added successfully.",
                    "data_added": add_list,
                    "remove_list": remove_list,
                    "data_skiped": skip_list,
                },
                status=status.HTTP_200_OK
            )


class ExtraChargesGeneralList(APIView):
    def post(self, request):
        required_fields = [
          "quantity"
        ]
        data = request.data
        # Iterate through each field and check if it's null or empty
        for field in required_fields:
            value = data.get(field)
            # If any required field is missing or empty
            if value is None or (isinstance(value, str) and value.strip() == ''):
                # Return error response and stop the process
                return Response({
                    "status_code": 400,
                    "status": "error",
                    "message": f"The field '{field}' is required and cannot be null or empty."
                }, status=status.HTTP_400_BAD_REQUEST)
        extra_charges = ExtraCharges.objects.filter(IsDeleted=False).order_by('OrderIndex', 'IsExxon')
        extra_charge_serializer = ExtraChargeGeneralSerializer(extra_charges, many=True,  context={'quantity': data.get('quantity')})

        if extra_charge_serializer.data:
            # for item in serializer.data:
            #     if item.get('Rate') == '':
            #         if item['ChargeName'] == '€13/MT surcharge for deliveries of 20-25MT, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)':
            #             item['Rate'] = request.data.get('quantity') * 13
            #         elif item['ChargeName'] == '€30/MT surcharge for deliveries of 15-20MT, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)':
            #             item['Rate'] = request.data.get('quantity') * 30
            #         elif item['ChargeName'] == '€55/MT surcharge for deliveries of 10-15MT, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)':
            #             item['Rate'] = request.data.get('quantity') * 55
            #         elif item['ChargeName'] == '€283/MT surcharge for deliveries of 5MT or less, (specifically for Exxon Group, Rotterdam, and product 30102 - H2SO4 T 96%)':
            #             item['Rate'] = request.data.get('quantity') * 283

            return Response(
                {
                    "status_code": 200,
                    "status": "success",
                    "message": "Extra charge list fetched successfully.",
                    "data": extra_charge_serializer.data
                },
                status=status.HTTP_200_OK
            )
        else:
            return Response(
                {
                    "status_code": 200,
                    "status": "success",
                    "message": "No charges found",
                    "data": []
                },
                status=status.HTTP_200_OK
            )


class UpdateOrderRequestView(APIView):
    """Api to edit order request"""

    @transaction.atomic
    def post(self, request):
        """
        API to update order details.
        """
        data = request.data
        serializer = purchase_serializer.UpdateOrderSerializer(data=data)

        if serializer.is_valid(raise_exception=True):
            validated_data = serializer.validated_data
            if 'exact_order_no' in validated_data.keys():
                existing_order = OrderRequests.objects.exclude(Id=data['order_id']).filter(
                    ExactOrderNo=data['exact_order_no'], IsDeleted=False).exists()
                if existing_order:
                    raise ValidationError({
                        "status_code": 400,
                        "status": "error",
                        "message": f"Exact order number {validated_data['exact_order_no']}already exists ",
                        "data": None
                    })

                # update Order request
                try:
                    order_request = OrderRequests.objects.get(Id=data['order_id'])
                except Exception as e:
                    raise ValidationError({
                        "status_code": 500,
                        "status": "error",
                        "message": f"Something went wrong: {e}",
                        "data": None
                    })

                order_request.ExactOrderNo = validated_data['exact_order_no']
                if 'IsTransporterReqestedChanges' in validated_data.keys():
                    has_extra_cost = validated_data['IsTransporterReqestedChanges']
                    order_request.HasTransporterReqestedChanges=has_extra_cost

                order_request.save()

                # update Order
                try:
                    order = Orders.objects.get(OrderNo=validated_data['order_id'], IsDeleted=False)
                except Exception as e:
                    raise ValidationError({
                        "status_code": 500,
                        "status": "error",
                        "message": f"Something went wrong {e}",
                        "data": None
                    })
                order.ExactOrderNo = validated_data.get('exact_order_no')
                order.save()

        return JsonResponse({
                        "status_code": 200,
                        "status": "success",
                        "message": f"Data Saved successfully",
                    }, status=status.HTTP_200_OK)


class GetMultimodelView(APIView):
    """Api to edit order request"""

    def post(self, request):
        """
        API to retrieves data for multiple models related to Dangerous Goods
        """
        data = request.data

        if not data.get('order_request_id'):
            return Response({
                "status_code": 400,
                "status": "error",
                "message": "Order request id is required"
            }, status=status.HTTP_400_BAD_REQUEST)

        order_request_id = data.get('order_request_id')

        try:
            order_request = OrderRequests.objects.get(Id=order_request_id)
        except ObjectDoesNotExist:
            return Response({
                "status_code": 404,
                "status": "error",
                "message": "Order request not found",
                "data": None
            }, status=status.HTTP_404_NOT_FOUND)

        result = purchase_serializer.MDGFormSerializer(order_request).data

        return Response(
            {
                "status_code": 200,
                "status": "success",
                "message": "Extra charge list fetched successfully.",
                "data": result
            },
            status=status.HTTP_200_OK
        )


class PackingDetailView(APIView):

    def get(self, request):
        """
        API to retrieves data for packaging goods
        """
        order_request_id = request.GET.get('order_request_id', None)
        product_id = request.GET.get('product_id', None)

        if not order_request_id:
            return Response({
                "status_code": 400,
                "status": "error",
                "message": "Order request id is required"
            }, status=status.HTTP_400_BAD_REQUEST)

        try:
            order_request = po_models.OrderRequests.objects.get(Id=order_request_id)
        except ObjectDoesNotExist:
            return Response({
                "status_code": 404,
                "status": "error",
                "message": "Order request not found",
                "data": None
            }, status=status.HTTP_404_NOT_FOUND)


        packing_data = purchase_utils.get_package_info(order_request, product_id)

        return Response(
            {
                "status_code": 200,
                "status": "success",
                "message": "Package data fetched successfully.",
                "data": packing_data
            },
            status=status.HTTP_200_OK
        )


class PackageDocumentView(APIView):

    def get(self, request):
        """
        API to retrieves data for packaging list document
        """
        order_request_id = request.GET.get('order_request_id', None)

        if not order_request_id:
            return Response({
                "status_code": 400,
                "status": "error",
                "message": "Order request id is required"
            }, status=status.HTTP_400_BAD_REQUEST)

        try:
            order_request = po_models.OrderRequests.objects.get(Id=order_request_id)
            order = po_models.Orders.objects.get(OrderNo=order_request_id)
            exact_order_no = order_request.ExactOrderNo
            LoadingDate = order.LoadingDate
            client_reference_no = order_request.PurchaseOrderNo
            DeliverTo = order_request.DeliverTo
            address_data = None
            if DeliverTo is not None:
                address_data = get_address_data(request.headers.get('x-auth-token'), DeliverTo)
        except ObjectDoesNotExist:
            return Response({
                "status_code": 404,
                "status": "error",
                "message": "Order request not found",
                "data": None
            }, status=status.HTTP_404_NOT_FOUND)

        packagelist_data = purchase_utils.get_quantity_summary(order_request)
        packagelist_data['client_reference_no'] = client_reference_no
        packagelist_data['exact_order_no'] = exact_order_no
        packagelist_data['loading_date'] = LoadingDate.strftime('%d-%m-%Y')
        packagelist_data['address_data'] = address_data
        

        return Response(
            {
                "status_code": 200,
                "status": "success",
                "message": "Packing list data fetched successfully.",
                "data": packagelist_data
            },
            status=status.HTTP_200_OK
        )


class OrderCancellationMailView(APIView):

    def post(self, request, *args, **kwargs):
        """ function to retrieve multiple order cancellation details to notify transporter"""

        required_fields = ["order_ids", "type"]
        missing_fields = [field for field in required_fields if not request.data.get(field)]

        if missing_fields:
            return Response(
                {
                    "status_code": 400,
                    "status": "error",
                    "message": f"Missing required field(s): {', '.join(missing_fields)}.",
                    "data": None
                },
                status=status.HTTP_400_BAD_REQUEST
            )

        order_ids = request.data.get('order_ids')
        receiver = request.data.get('type')

        orders = Orders.objects.filter(OrderNo__in=order_ids, IsDeleted=False).order_by('ExactOrderNo')
        cancellation_required_orders = orders.all()

        for order in orders:
            if receiver=='customer':
                history = EmailLog.objects.filter(
                    type='customer', order_id=order.OrderNo, status='success').values(
                        'type', 'receipient_id')
                # if no mail history found, no need to send cancellation mail
                if not history:
                    cancellation_required_orders = cancellation_required_orders.exclude(Id=order.Id)
            elif receiver=='transporter':
                transporter_id = order.TransporterId

                if order.IncoTerm=='FCA':
                    raise ValidationError({
                        "status_code": 400,
                        "status": "error",
                        "message": f"Transport Mail is not generated since Incoterm is FCA",
                        "data": ""
                    })

                history = EmailLog.objects.filter(
                    type='transporter', order_id=order.OrderNo, status='success')

                if not history:
                    cancellation_required_orders = cancellation_required_orders.exclude(Id=order.Id)
                elif history.last().receipient_id!=transporter_id:
                    cancellation_required_orders = cancellation_required_orders.exclude(Id=order.Id)
            elif receiver == 'lab':
                lab_types = ['taken_from_same_batch',
                    'analyzed_by_customer', 
                    'taken_from_truck', 
                    'taken_from_other_customer', 
                  
                ]
                history = EmailLog.objects.filter(
                    type__in=lab_types, order_id=order.OrderNo, status='success')
                if not history:
                    cancellation_required_orders = cancellation_required_orders.exclude(Id=order.Id)

            elif receiver == 'courier':
                history = EmailLog.objects.filter(
                    type='courier', order_id=order.OrderNo, status='success')
                if not history:
                    cancellation_required_orders = cancellation_required_orders.exclude(Id=order.Id)

        if not cancellation_required_orders:
            raise ValidationError({
                "status_code": 400,
                "status": "error",
                "message": f"Cancellation Email not required as no confirmation mail has been sent",
                "data": ""
            })


        transport_mail_serializer = purchase_serializer.TransportMailSerializer(cancellation_required_orders[0], context={'request': request})
        order_data = transport_mail_serializer.data

        if not orders:
            return Response(
                {
                    "status_code": 400,
                    "status": "error",
                    "message": f"The orders for id {order_ids} not found ",
                    "data": None
                },
                status=status.HTTP_400_BAD_REQUEST
            )
        purchase_utils.validate_orders(orders)

        if orders.exists():
            response_data = purchase_utils.get_cancellation_data(cancellation_required_orders, order_data, receiver)

            # Return data as JSON instead of generating a PDF 
            return Response(
                {
                    "status_code": 200,
                    "status": "success",
                    "message": "Mail data retrieved successfully",
                    "data": response_data
                },
                status=status.HTTP_200_OK
            )

        else:
            return Response(
                {
                    'status_code': status.HTTP_404_NOT_FOUND,
                    'status': "error",
                    'message': "No orders found",
                    'data': None,
                },
                status=status.HTTP_404_NOT_FOUND
            )




class GetAllOrder(APIView):
    """function to retrieve all orders data """
    def get(self, request):
        orders = Orders.objects.all()
        order_data = purchase_serializer.AllOrderSerializer(orders, many=True).data

        return Response(
            {
                "status_code": 200,
                "status": "success",
                "message": "Extra charge list fetched successfully.",
                "data": order_data
            },
            status=status.HTTP_200_OK
        )


class GetAllOrderRequests(APIView):
    """function to retrieve all orders data """

    def get(self, request):
        ordersReqs = OrderRequests.objects.all()
        order_data = purchase_serializer.AllOrderRequestSerializer(ordersReqs, many=True).data

        return Response(
            {
                "status_code": 200,
                "status": "success",
                "message": "Extra charge list fetched successfully.",
                "data": order_data
            },
            status=status.HTTP_200_OK
        )

class GetEmailDataView(APIView):

    def get(self, request, *args, **kwargs):
        """Api to get content data for lab, courrier mails"""
        order_id = request.GET.get('order_id')
        email_type = request.GET.get('email_type')
        login_user_email = request.login_user_email
        login_user = request.login_user_name
        login_user_role = request.login_user_role

        if not order_id:
            return Response(
                {
                    "status_code": 400,
                    "status": "error",
                    "message": "The 'order_id' field is required.",
                    "data": None
                },
                status=status.HTTP_400_BAD_REQUEST
            )
        try:
            order = Orders.objects.get(OrderNo=order_id, IsDeleted=False)
            order_request = OrderRequests.objects.get(Id=order_id)
        except:
            raise ValidationError({
                "status_code": 400,
                "status": "error",
                "message": f"Order Not Found",
                "data": ""
            })
        if order:
            order_data = OrderDetailsSerializer(order, context={'request': request}).data


            get_content = {
                'taken_from_same_batch': purchase_utils.get_email_content_for_taken_from_same_batch(order, order_request, order_data),
                'analyzed_by_customer': purchase_utils.get_email_content_for_analyzed_by_customer(order, order_request, order_data),  
                'taken_from_truck': purchase_utils.get_email_content_for_option_1(order, order_request, order_data), 
                'taken_from_other_customer': purchase_utils.get_email_content_for_option_2(order, order_request, order_data), 
                'courier': purchase_utils.get_email_content_courier(order, order_request, order_data)
            } 

            response_data = get_content[email_type]

            emaildraft = po_models.EmailDraft.objects.filter(
                    order_request_id=order_id, is_deleted=False, email_type=email_type).first()
            if emaildraft:
                response_data['email_body'] = emaildraft.body
                response_data['subject'] = emaildraft.subject

            if login_user_email not in response_data['cc_mail']:
                response_data['cc_mail'].append(login_user_email)
            response_data['login_user'] = login_user
            response_data['login_user_email'] = login_user_email
            response_data['login_user_role'] = login_user_role
            
            return Response(
                {
                    'status_code': status.HTTP_200_OK,
                    'status': "success",
                    'message': "orders found",
                    'data': response_data,
                },
                status=status.HTTP_200_OK
            )
        else:
            return Response(
                {
                    'status_code': status.HTTP_404_NOT_FOUND,
                    'status': "error",
                    'message': "No orders found",
                    'data': None,
                },
                status=status.HTTP_404_NOT_FOUND
            )
        

class CheckReplanView(APIView):

    def post(self, request, *args, **kwargs):
        """ function to retrieve multiple order cancellation details to notify transporter"""

        login_user_email = request.login_user_email

        required_fields = ["orderId", "type"] 

        missing_fields = [field for field in required_fields if not request.data.get(field)]

        if missing_fields:
            return Response(
                {
                    "status_code": 400,
                    "status": "error",
                    "message": f"Missing required field(s): {', '.join(missing_fields)}.",
                    "data": None
                },
                status=status.HTTP_400_BAD_REQUEST
            )
        order_id = request.data.get('orderId')
        changed_fields = request.data.get('changedFields')
        replan_type = request.data.get('type')
        receipient_id = request.data.get('receipient_id', None)

        try:
            order = Orders.objects.get(OrderNo=order_id, IsDeleted=False)
        except:
            raise ValidationError({
                "status_code": 400,
                "status": "error",
                "message": f"Order Not Found",
                "data": ""
            })
        
        response_data = purchase_utils.get_replan_content_data(
            order, replan_type, receipient_id, changed_fields, request)

        if order:

            return Response(
                {
                    'status_code': status.HTTP_200_OK,
                    'status': "success",
                    'message': "orders found",
                    'data': response_data,
                },
                status=status.HTTP_200_OK
            )
        else:
            return Response(
                {
                    'status_code': status.HTTP_404_NOT_FOUND,
                    'status': "error",
                    'message': "No orders found",
                    'data': None,
                },
                status=status.HTTP_404_NOT_FOUND
            )



class CustomerRequirementView(APIView):

    def post(self, request, *args, **kwargs):
        """ Funtion to get data for customer based requirements"""

        required_fields = ["ShipTo"] 

        missing_fields = [field for field in required_fields if not request.data.get(field)]

        if missing_fields:
            return Response(
                {
                    "status_code": 400,
                    "status": "error",
                    "message": f"Missing required field(s): {', '.join(missing_fields)}.",
                    "data": None
                },
                status=status.HTTP_400_BAD_REQUEST
            )

        ship_to = request.data.get("ShipTo")
        data = request.data

        try:
            requirement = po_models.CustomerRequirement.objects.get(ShipTo=ship_to)
            serializer = purchase_serializer.CustomerRequirementSerializer(
                    instance=requirement, data=data, partial=True)
            if serializer.is_valid():
                serializer.save()
        except:
            raise ValidationError({
                "status_code": 400,
                "status": "error",
                "message": f"Requirement Not Found",
                "data": ""
            })
        
        if requirement:
            return Response(
                {
                    'status_code': status.HTTP_200_OK,
                    'status': "success",
                    'message': "Requirement updated",
                    'data': serializer.data,
                },
                status=status.HTTP_200_OK
            )
        else:
            return Response(
                {
                    'status_code': status.HTTP_404_NOT_FOUND,
                    'status': "error",
                    'message': "Requirements Not Updated",
                    'data': None,
                },
                status=status.HTTP_404_NOT_FOUND
            )
        

from django.http import FileResponse, Http404

def serve_media_file(request, file_path):
    """Serve media files with CORS headers"""
    
    file_full_path = os.path.join(settings.MEDIA_ROOT, file_path)
    
    if not os.path.exists(file_full_path):
        raise Http404("File not found")
    
    response = FileResponse(open(file_full_path, 'rb'))
    
    # Add CORS headers
    response['Access-Control-Allow-Origin'] = '*'
    response['Access-Control-Allow-Methods'] = 'GET, OPTIONS'
    response['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
    response['Cross-Origin-Resource-Policy'] = 'cross-origin'
    
    # Set content type based on file extension
    if file_path.endswith('.pdf'):
        response['Content-Type'] = 'application/pdf'
    elif file_path.endswith(('.jpg', '.jpeg')):
        response['Content-Type'] = 'image/jpeg'
    elif file_path.endswith('.png'):
        response['Content-Type'] = 'image/png'
    
    return response


class EmailDraftView(APIView):
    def post(self, request, *args, **kwargs):
        """function to create email draft"""

        data = request.data

        order_request_id = data.get("order_request_id")
        email_type = data.get("email_type")
        subject = data.get("subject")
        body = data.get("body")
        attachments = request.FILES.getlist("attachments")

        mandatory_fields = ["order_request_id", "email_type"]
        missing_fields = [field for field in mandatory_fields if not data.get(field)]
        if missing_fields:
            return Response(
                {
                    'status_code': status.HTTP_400_BAD_REQUEST,
                    'status': "error",
                    'message': f"Missing required field(s): {', '.join(missing_fields)}.",
                    'data': None,
                },
                status=status.HTTP_400_BAD_REQUEST)


        # if draft existing in order id then update it else create draft instance
        draft = po_models.EmailDraft.objects.filter(
            order_request_id=order_request_id, email_type=email_type).first()
        if draft:
            draft.subject = subject
            draft.body = body
            draft.attachments = attachments
            draft.save()
        else:
            draft = po_models.EmailDraft.objects.create(
                order_request_id=order_request_id,
                email_type=email_type,
                subject=subject,
                body=body,
            )
        # delete all existing attachments
        po_models.EmailDraftAttachment.objects.filter(email_draft_id=draft.id).delete()
        if attachments:
            for attachment in attachments:
                po_models.EmailDraftAttachment.objects.create(
                    email_draft_id=draft.id,
                    attachment=attachment
                )

        return Response(
                {
                    'status_code': status.HTTP_200_OK,
                    'status': "success",
                    'message': "Email draft created successfully",
                    'data': None,
                },
                status=status.HTTP_200_OK)
        

        
    def get(self, request, *args, **kwargs):
        """Api to get data for email draft"""
        
        order_id = request.query_params.get('order_id')
        email_type = request.query_params.get('email_type')

        try:
            draft_instance = po_models.EmailDraft.objects.get(order_request_id=order_id, email_type=email_type)
        except po_models.EmailDraft.DoesNotExist:
            return Response(
                {
                    'status_code': status.HTTP_400_BAD_REQUEST,
                    'status': "error",
                    'message': f"Draft Not Found",
                    'data': None,
                },
                status=status.HTTP_400_BAD_REQUEST)
        except po_models.EmailDraft.MultipleObjectsReturned:
            return Response(
                {
                    'status_code': status.HTTP_400_BAD_REQUEST,
                    'status': "error",
                    'message': f"Multiple Drafts Found",
                    'data': None,
                },
                status=status.HTTP_400_BAD_REQUEST)

        serializer = purchase_serializer.EmailDraftSerializer(draft_instance)
        return Response(
            {
                'status_code': status.HTTP_200_OK,
                'status': "success",
                'message': "Email draft found",
                'data': serializer.data,
            },
            status=status.HTTP_200_OK)


class PackageMasterView(APIView):
    """class to manage package master data"""

    def get(self, request, *args, **kwargs):
        """Api to get data for email draft"""
        
        search_key = request.query_params.get('search', '')

        try:
            erp_client = OdooAPIService()
            package_master_data = erp_client.get_package_master_data()
        except Exception as e:
            return Response(
                {
                    'status_code': status.HTTP_400_BAD_REQUEST,
                    'status': "error",
                    'message': f"Package data not found: {str(e)}",
                    'data': None,
                },
                status=status.HTTP_400_BAD_REQUEST)

        return Response(
            {
                'status_code': status.HTTP_200_OK,
                'status': "success",
                'message': "Email draft found",
                'data': package_master_data.get('data', []),
            },
            status=status.HTTP_200_OK)


class GetCustomerRequirementView(APIView):
    """
    API View to return customer requirement data from Odoo.
    GET API taking shiptocode and articlecode parameters.
    Uses get_customer_requirements from OdooAPIService.
    """
    def get(self, request, *args, **kwargs):
        ship_to_code = request.query_params.get('shiptocode') or request.query_params.get('ship_to_code', '')
        article_code = request.query_params.get('articlecode') or request.query_params.get('article_code', '')

        if not ship_to_code or not article_code:
            return Response(
                {
                    'status_code': status.HTTP_400_BAD_REQUEST,
                    'status': "error",
                    'message': "shiptocode and articlecode query parameters are required.",
                    'data': None,
                },
                status=status.HTTP_400_BAD_REQUEST
            )

        try:
            params = {
                "ship_to_code": ship_to_code,
                "article_code": article_code
            }
            erp_client = OdooAPIService()
            response_data = erp_client.get_customer_requirements(params=params)

            odoo_data = response_data.get('data') if isinstance(response_data, dict) else None
            has_data = isinstance(odoo_data, dict) and bool(odoo_data)

            if has_data:
                redirect_url = odoo_data.get('record_url')
                instruction_data = odoo_data
            else:
                redirect_url = response_data.get('create_url') if isinstance(response_data, dict) else None
                instruction_data = odoo_data if isinstance(odoo_data, dict) else {}

            return Response({
                'status_code': status.HTTP_200_OK,
                'status': "success",
                'message': "Customer requirement data fetched successfully",
                'data': {
                    'is_instruction_master_available': has_data,
                    'redirect_url': redirect_url,
                    'instruction_data': instruction_data
                }
            }, status=status.HTTP_200_OK)
        except Exception as e:
            return Response(
                {
                    'status_code': status.HTTP_500_INTERNAL_SERVER_ERROR,
                    'status': "error",
                    'message': f"An error occurred while fetching customer requirement data from Odoo: {str(e)}",
                    'data': None
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )