from django.shortcuts import render, get_object_or_404, redirect
from django.urls import reverse
from django.http import HttpResponse, JsonResponse, HttpResponseRedirect
from django.forms import modelformset_factory, inlineformset_factory
from django.db import transaction
from django.core import serializers
from .models import Invoice, InvoiceItemLine
from Item.models import Item, PriceLevel, PriceLevelItem
from Customer.models import Customer
from .forms import InvoiceForm, InvoiceItemLineForm, GeeksForm
import json
from django.core.serializers.json import DjangoJSONEncoder
from django.contrib import messages
import os
import pandas as pd
from django.conf import settings
# from icecream import ic
import timeit
from decimal import Decimal
from  datetime import datetime

# ic.configureOutput(includeContext= True)

def get_SalesOrderQuery(customer_name, txnid=None):
    try:
        print("try")
        from  SO_to_Inv.readSO import SalesOrderQuery

    except:
        import sys
        sys.path.append('.')
        sys.path.append('..')
        print("except")
        print(sys.path)
        from  SO_to_Inv.readSO import SalesOrderQuery
        print("salesorderquery imported")
    # print(os.getcwd())
    # parentdir = os.path.dirname(os.getcwd())
    # print(parentdir)
    

    basedir = settings.BASE_DIR
    parentdir = os.path.dirname(basedir)
    if txnid:
        ini=SalesOrderQuery(FullName= customer_name, TxnID=txnid, IncludeRetElement = ['TxnID', 'TimeCreated', 'TimeModified','TxnNumber', 'CustomerRef', 'TxnDate', 'RefNumber', 'IsManuallyClosed', 'IsFullyInvoiced','TotalAmount'], cwd=parentdir)
        pass
    else:
        ini=SalesOrderQuery(FullName= customer_name, IncludeRetElement = ['TxnID', 'TimeCreated', 'TimeModified','TxnNumber', 'CustomerRef', 'TxnDate', 'RefNumber', 'IsManuallyClosed', 'IsFullyInvoiced','TotalAmount'], cwd=parentdir)
    return ini

def get_TransactionQuery(txnid=None, refnumber=None, customername=None, txntypefilter=None, includeret=[ 'TxnID', 'EntityRef', 'TxnDate', 'RefNumber', 'Memo'] ):
    try:
        print("try")
        from  qbtransactionquery import TransactionQuery

    except:
        import sys
        sys.path.append('.')
        sys.path.append('..')
        print("except")
        print(sys.path)
        from  qbtransactionquery import TransactionQuery
        print("transactionquery imported")

    basedir = settings.BASE_DIR
    parentdir = os.path.dirname(basedir)
    if txnid:
        ini=TransactionQuery(FullName= customername, RefNumber = refnumber, TxnID=txnid, IncludeRetElement = includeret, cwd=parentdir)
    else:
        ini=TransactionQuery(FullName= customername, RefNumber = refnumber, IncludeRetElement =includeret, cwd=parentdir)
    return ini


def show_customer(request):
    pass
    print("show_customer")
    starttime = timeit.default_timer()
    # thispath = os.getcwd()
    # print(thispath)
    basedir = settings.BASE_DIR
    parent = os.path.dirname(basedir)
    print(f'parent dir= {parent}')
    print(f"Base_DIR: {settings.BASE_DIR}")
    customers_file = os.path.join(parent, "ItemInventory", "CustomerList.xlsx")
    df = pd.read_excel(customers_file, usecols=["FullName"])
    
    context={"customers": df.values.tolist()}
    if request.method =="POST":
        customer_name = request.POST.get("customerreffullname")
        print(f'customer_name: {customer_name}')
        # context['objects'] = [['abc', 'def', 'ghi', 'jkl']]
        context['objects'] = []
        print("The time difference is bef show customer :", timeit.default_timer() - starttime)

        if customer_name:
            ini = get_SalesOrderQuery(customer_name)
            print("The time difference is mid show customer :", timeit.default_timer() - starttime)
            if ini:
                print("after ini show customer")
                qbxml = ini.create_QBXML()
                # print(qbxml)
                print("The time difference is :", timeit.default_timer() - starttime)
                print("timeeint")
                response_string = ini.connect_to_quickbooks(qbxml)
                # print(response_string)
                open_sales_orders = ini.get_open_so()
                print(f'open sales orders showcustomer:{open_sales_orders}')
                ini=None
                if not open_sales_orders:
                    messages.info(request, f"There is No open SO for {customer_name}")
                    return redirect("Invoice:show_customer")
                # if open_sales_orders:
                context['objects'] = open_sales_orders
                    

                context['customer_fullname'] = customer_name
                print("The time difference is :", timeit.default_timer() - starttime)
                return render(request, "Invoice/so_list_form.html", context)
    # print(df.values.tolist())
    print("The time difference is :", timeit.default_timer() - starttime)
    return render(request, "Invoice/show-customers.html", context)


def select_so(request):
    pass

def choose_inv(request):
    print("choose_inv")
    starttime = timeit.default_timer()    

    context={}
    if request.method == "POST":
        print(request.POST)
        data = dict(request.POST)
        del data['csrfmiddlewaretoken']
        del data['customer_fullname']
        # if 'other_items' in data:
        #     del data['other_items']
        #     del data['other_qty']
        #     del data['other_rate']
        #     del data['selected_items']

        print(f"datadict:{data}")
        try:
            df = pd.DataFrame(data)
            print(df)
        except:
            print(Exception)
            return HttpResponse("DataFrame Error")
        print(f'json:{df.to_json(orient="records")}')
        print(df.to_dict("records"))
        
        if ('so_field' in request.POST) and ('customer_fullname' in request.POST):
            print(request.POST.getlist('so_field'))
            open_sales_orders_TxnID = request.POST.getlist('so_field')
            customer_fullname = request.POST.get('customer_fullname')
            print(f'Customer_fullname:{customer_fullname} -> request values:{open_sales_orders_TxnID}')
            ### get the SO detail
            ini=get_SalesOrderQuery(customer_fullname, open_sales_orders_TxnID)
            # ini=get_SalesOrderQuery(customer_fullname)
            print("")
            print("The time difference chooseinv is :", timeit.default_timer() - starttime)
            print(f'ini::{ini}')
            print("The time difference chooseinv is :", timeit.default_timer() - starttime)
            print("before ITU")
            itu = ini.get_open_sales_order(open_sales_orders_TxnID)
            # print(itu)
            print("The time difference  after itu is :", timeit.default_timer() - starttime)
            print(f'get_open_sales_order:{itu}')
            if itu:
                context['objects'] = itu
                context['customer_fullname'] = customer_fullname
                # print("Invoiceaddqbxml:")
                # invoiceaddQBXML=ini.create_invoiceadd_QBXML()
                
                # print(invoiceaddQBXML)
                # print("")
                # result=None
                # print("")
                # result = ini.connect_to_quickbooks(ini.create_invoiceadd_QBXML())
                # print("RESULT:")
                # print(result)
                print("The time difference finish choose inv is :", timeit.default_timer() - starttime)

                return render(request, "Invoice/so_details_form.html", context)
            else:
                messages.warning(request, "Customer PriceLevel or PriceLevelList not found. please prepare data first and check Customer 'Special Customer Custom Field'")
        elif 'customer_fullname' in request.POST:
            customer_name = request.POST.get('customer_fullname')
            ini = get_SalesOrderQuery(customer_name)
            if ini:
                print("after ini")
                qbxml = ini.create_QBXML()
                # print(qbxml)
                response_string = ini.connect_to_quickbooks(qbxml)
                print(response_string)
                open_sales_orders = ini.get_open_so()
                print(f'open sales orders:{open_sales_orders}')
                ini=None
                if open_sales_orders:
                    context['objects'] = open_sales_orders
                    

                context['customer_fullname'] = customer_name
    print("The time difference is :", timeit.default_timer() - starttime)

    return render( request, "Invoice/so_list_form.html", context)
    # return HttpResponse('')


def unique(list1):
 
    # insert the list to the set
    list_set = set(list1)
    # convert the set to the list
    unique_list = (list(list_set))
    return unique_list

def check_duplicate_refnumber(refnumber):
    ini = get_TransactionQuery(refnumber=refnumber, includeret=['TxnID', 'RefNumber'])
    status, statuscode = ini.status_ok(ini.connect_to_quickbooks(ini.create_QBXML()))
    print(f'check duplicate refnumber:{status}; {statuscode}')
    return status   ### status=True -> duplicate refnumber
        

def save_inv(request):
    print("save_inv")
    starttime = timeit.default_timer()
    context={}
    if request.method == "POST":
        # print(request.POST)
        data = dict(request.POST)
        del data['csrfmiddlewaretoken']
        del data['customer_fullname']
        ### get others items into list of dict ###
        others=[]
        otherFullName = {'peti': 'PETI', 'expedition':'Sales_Ekspedisi'}
        ref_number = request.POST.get('ref_number', None)
        txn_date = request.POST.get('date', None)
        print(ref_number, txn_date)
        if len(ref_number)>20:
            return HttpResponse("RefNumber Invalid. ")
        elif ref_number.strip()=="":
            ref_number = None
        if ref_number and check_duplicate_refnumber(ref_number):
            messages.warning(request, 'RefNumber already Exist. please choose other RefNumber')
            return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
            return HttpResponse('RefNumber already Exist. please choose other RefNumber')
        if len(txn_date)<6:
            return HttpResponse("Date is Invalid")
        del data['ref_number']
        del data['date']
        if 'selected_items' in data:
            for _ in data['selected_items']:
                if _ in data['other_items']:
                    data_idx = data['other_items'].index(_)
                    print(f'selected item:{_} is in index:{data_idx}')
                    other_qty = int(data['other_qty'][data_idx])
                    other_rate = float(data['other_rate'][data_idx])
                    if other_qty<=0:
                        other_qty = 1
                    if other_rate <= 0:
                        continue
                    temp_ = {'other_item':data['other_items'][data_idx], 'other_itemFullName': otherFullName[data['other_items'][data_idx]], 'other_qty':other_qty, 'other_rate': other_rate}
                    others.append(temp_)
            del data['selected_items']
        if 'other_items' in data:
            del data['other_items']
        if 'other_qty' in data:
            del data['other_qty']
        if 'other_rate' in data:
            del data['other_rate']
        print(f'others:{others}')

        print(f"datadict:{data}")
        required_data = ['RefNumber', 'CustomerFullName', 'TxnID', 'TxnDate', 'TotalAmount', 'TxnLineID', 'ItemFullName',
                         'Quantity', 'UOM', 'Rate', 'Amount', 'Invoiced', 'LineIsManuallyClosed', 'backordered', 'rate', 'convertQTY']
        if 'so_field' not in data:
            return HttpResponse("no Selected Items. Please select at least 1 item to be invoiced.")
        for _ in required_data:
            if _ not in data:
                return HttpResponse(f"Required data not returned from the form: {_}")
        
        ### retrieve only the selected so_field ###
        so_field = data['so_field']
        del data['so_field']
        selectedItems = []
        for _ in so_field:
            if _ not in data['TxnLineID']:
                return HttpResponse(f"One of the TxnLineID is not valid: {_}")
            data_idx = data['TxnLineID'].index(_)
        try:
            df = pd.DataFrame(data)
            print(df)
            df = df[df['TxnLineID'].isin(so_field)].reset_index()
            print(df)
        except:
            print(Exception)
            return HttpResponse("DataFrame Error")
        # print(f'json:{df.to_json(orient="records")}')
        web_dict = df.to_dict("records")
        # print(f'web_dict:{web_dict}' )
        web_dict = sorted(web_dict, key=lambda x: x['TxnID'])
        # print(f'Sorted web_dict:{web_dict}' )
        if ('so_field' in request.POST) and ('customer_fullname' in request.POST):
            print(request.POST.getlist('so_field'))
            # open_sales_orders_TxnID = unique(request.POST.getlist('so_field'))
            open_sales_orders_TxnID = unique(df['TxnID'].to_list())
            customer_fullname = request.POST.get('customer_fullname')
            print(f'Customer_fullname:{customer_fullname} -> request values:{open_sales_orders_TxnID}')
            ### get the SO detail
            ini=get_SalesOrderQuery(customer_fullname)
            print(f'ini::{ini}')
            print("before ITU")
            itu = ini.get_open_sales_order(open_sales_orders_TxnID)
            # print(itu)
            itu = sorted(itu, key=lambda x: x['TxnID'])
            print(f'get_open_sales_order:{itu}')
            if itu:
                ### do the checking web_dict and openSO ###
                data_to_save = []
                dict_ = {}
                txnids = []
                disc_amount = 0
                for web in web_dict:
                    for tu_ in itu:
                        # print(tu_)
                        if web['TxnID'] == tu_['TxnID'] and web['TxnDate'] == tu_['TxnDate'] and web['RefNumber'] == tu_['RefNumber']:
                            if web['TxnID'] not in txnids:  # new txn
                                if dict_:
                                    dict_['Disc_Amount']=disc_amount
                                    data_to_save.append(dict_)
                                dict_ = {'RefNumber': web['RefNumber'], 'CustomerFullName': tu_['CustomerFullName'], 'TxnID': web['TxnID'],
                                     'TxnDate': web['TxnDate'], 'TxnNumber': tu_['TxnNumber'],
                                     'TotalAmount': '0.00', 'IsFullyInvoiced': tu_['IsFullyInvoiced'], 'IsManuallyClosed': tu_['IsManuallyClosed'],
                                     'SalesOrderLineRet': [] } 
                                disc_amount = 0
                            txnids.append(web['TxnID'])
                            txnids = unique(txnids) ### not usefull
                            for tu_line_ret in tu_['SalesOrderLineRet']:
                                # print(tu_line_ret)
                                if web['TxnLineID']==tu_line_ret['TxnLineID'] and web['ItemFullName']==tu_line_ret['ItemFullName']:
                                    ### modified back the rate and backordered using convertQTY ###
                                    convertQTY = int(tu_line_ret['convertQTY'])
                                    webbackordered = Decimal(web['backordered']) * convertQTY
                                    webrate = Decimal(web['rate']) / convertQTY
                                    ###
                                    if 0 < webbackordered <= Decimal(tu_line_ret['BackOrdered']):
                                        # print('put in list')
                                        discPerPcs=0
                                        discPerItem=0
                                        if webrate == Decimal(tu_line_ret['Rate']):
                                            discPerPcs = ini.get_discperpcs(web['ItemFullName'], webrate)
                                        elif webrate < Decimal(tu_line_ret['Rate']):
                                            discPerPcs = Decimal(tu_line_ret['Rate']) - webrate
                                        discPerItem = webbackordered * discPerPcs
                                        disc_amount += discPerItem

                                        SalesOrderLinedict = {'TxnLineID':web['TxnLineID'],
                                            'ItemFullName':tu_line_ret['ItemFullName'],
                                            'Quantity':tu_line_ret['Quantity'],
                                            'UOM':tu_line_ret['UOM'],
                                            'Rate':webrate,
                                            'Amount':Decimal(tu_line_ret['Amount']),
                                            'BackOrdered':webbackordered,
                                            'Invoiced':tu_line_ret['Invoiced'],
                                            'LineIsManuallyClosed':tu_line_ret['LineIsManuallyClosed'],
                                            'discPerItem':discPerItem,    # backorder qty * disc per pcs
                                            'discPerPcs':discPerPcs,
                                            'convertQTY':tu_line_ret['convertQTY']
                                            }
                                        # print(f'salesorderlineddict:{SalesOrderLinedict}')
                                        _salesorderlineret = dict_['SalesOrderLineRet']
                                        _salesorderlineret.append(SalesOrderLinedict)
                                        dict_['SalesOrderLineRet'] = _salesorderlineret
                                        
                                        break
                            break
                print(f'last:{dict_}')
                print(f'datatosaveonly:{data_to_save}')
                if not data_to_save:
                    dict_['Disc_Amount']=disc_amount
                    data_to_save.append(dict_)
                elif dict_ != data_to_save[-1]:   #append the last dict_
                    dict_['Disc_Amount']=disc_amount
                    data_to_save.append(dict_)
                    print('save the last dict')
                else:
                    print('last data to save == dict')
                for _ in others:
                    data_to_save.append(_)
                
                dict_to_save = {'customer_fullname': customer_fullname, 'ref_number':ref_number, 'txn_date':txn_date, 'data':data_to_save }
                print(f'Final List:{dict_to_save}')
                print("")
                # print(itu)
                context['objects'] = itu
                context['customer_fullname'] = customer_fullname
                # print(context['objects'])
                print("Invoiceaddqbxml:")
                invoiceaddQBXML=ini.create_invoiceadd_QBXML(dict_to_save)
                
                print(invoiceaddQBXML)
                result=None
                result = ini.connect_to_quickbooks(invoiceaddQBXML)
                print("RESULT:")
                print(result)
                rst, status_msg = ini.status_ok(result)
                if rst:
                    saved_inv = ini.get_saved_refnumber(result)
                    print(saved_inv)
                    # context['messages']=[{"alert":"info", "message": "invoice Is Good"}]
                    balance_remaining = "{:,}".format(float(saved_inv['BalanceRemaining']))
                    date_format = '%Y-%m-%d'
                    date_obj = datetime.strptime(saved_inv['TxnDate'], date_format).strftime('%d %b %Y')
                    messages.success(request, f"Customer : {saved_inv['Customer_FullName']}<br>Invoice No : {saved_inv['RefNumber']} &emsp; Date : {date_obj}<br>Invoice Amount : Rp. {balance_remaining}<br> Is SAVED with link to SO No. : {unique(df['RefNumber'].to_list())}<br>it takes {round(timeit.default_timer() - starttime, 4)} secs")
                    
                    # messages.info(request, 'Invoice Has Been SAVED2')
                else:
                    messages.warning(request, f"Error saving SO No. {unique(df['RefNumber'].to_list())}<br>Status: {status_msg}")
                print("The time difference finish Save Inv is :", timeit.default_timer() - starttime)

                return redirect('Invoice:show_customer')
                return render(request, "Invoice/show-customers.html", context)
                return render(request, "Invoice/so_details_form.html", context)
            else:
                return HttpResponse(f"You cannot Save, because There Is No Open Sales Order for Customer: {customer_fullname}")
        elif 'customer_fullname' in request.POST:
            customer_name = request.POST.get('customer_fullname')
            ini = get_SalesOrderQuery(customer_name)
            if ini:
                print("after ini")
                qbxml = ini.create_QBXML()
                # print(qbxml)
                response_string = ini.connect_to_quickbooks(qbxml)
                print(response_string)
                open_sales_orders = ini.get_open_so()
                print(f'open sales orders:{open_sales_orders}')
                ini=None
                if open_sales_orders:
                    context['objects'] = open_sales_orders
                    

                context['customer_fullname'] = customer_name
    
    return render( request, "Invoice/so_list_form.html", context)
    # return HttpResponse('')


def prepare_data(request):
    starttime = timeit.default_timer()
    import sys
    sys.path.append('.')
    sys.path.append('..')

    context = {}
    FullName = ""
    if request.method=='POST':
        print(request.POST)
        subject = request.POST.get("subject", None)
        print(subject, type(subject))
        if subject and isinstance(subject, str):
            ret=False
            # import sys
            # sys.path.append('.')
            # sys.path.append('..')
            if subject.upper() == "ITEM INVENTORY":
                # try:
                print("try iteminventory import")
                from  ItemInventoryQuery import ItemInventoryQuery

                ini= ItemInventoryQuery( OwnerID ="0")
                itu = ini.connect_to_quickbooks(ini.create_QBXML())
                ret, msg = ini.status_ok(itu)
                if ret:
                    print("YEAH")
                    df = pd.DataFrame.from_dict(ini.get_data(itu))
                    print(df)
                    df.to_excel('ItemInventory\ItemInventory_FromQB.xlsx', index=False)
                    modtime = datetime.fromtimestamp(os.path.getmtime('ItemInventory\ItemInventory_FromQB.xlsx'))
                    print(f"modified Time:{modtime}")
                    # print(ini.status_ok(itu))
                else:
                    messages.warning(request, f"Saving {subject} NOT success: {msg}")

            elif subject.upper() == "CUSTOMER LIST":
                # try:
                print("try customerlist import")
                from  SO_to_Inv.CustomerQuery import CustomerQuery

                ini=CustomerQuery()
                itu = ini.create_customerquery_QBXML()
                # print(f'itu:{itu}')
                print(f'get customer pricelevel list:{ini.get_customer_pricelevel_list(itu)}')
                ret=True
            elif subject.upper() == "PRICE LEVEL LIST":
                # try:
                print("try pricelevelquery import")
                from  SO_to_Inv.PriceLevelQuery import PriceLevelQuery
                
                FullName = ['t 202202', 'M 202202', 'b 202202', 'sp 202202']
                FullName = request.POST.getlist("selected_items", FullName)
                # print(f'fullname:{FullName}')
                ini = PriceLevelQuery(FullName = FullName, )
                itu = ini.connect_to_quickbooks(ini.create_QBXML())
                ret, msg = ini.get_pricelevel()
                ini= None
                itu = None
                if ret:
                    print(f'Success Save Price Level : {FullName}')

                else:
                    messages.warning(request, f"Saving Not Success. status: {msg}")
                    print(f"Saving Not Success. status: {msg}")
            if ret:
                # messages.info(request, "<p> You are <em>pretty</em><br> smart</p>")
                messages.info(request, f"{subject} has been updated Successfully in {round(timeit.default_timer() - starttime, 4)} seconds. {FullName}")

        else:
            messages.error(request, "not valid choice. Please choose again")
    # else:
    from  SO_to_Inv.PriceLevelQuery import PriceLevelQuery
    ini = PriceLevelQuery(IncludeRetElement = ['Name'])

    price_level_list = ini.name_list()
    # print(price_level_list)
    context['objects']=price_level_list

    print("The time difference is :", timeit.default_timer() - starttime)
    return render(request, "Invoice/prepare_data.html", context=context)


def index(request):
    print("index Inv")
    context = {}
    context['objects'] = Invoice.objects.order_by('-TimeCreated')
    context['addurl'] = reverse('Invoice:add_so')
    return render(request, "Invoice/index_invoice.html", context=context)
DEMO_CHOICES2 =(
    ("10", "Naveen"),
    ("20", "Pranav"),
    ("30", "Isha"),
    ("40", "Saloni"),
    ("50", "Sg"),
)
def home_view(request):
    if request.method == "POST":
        print(request.POST)
        if 'geeks_field' in request.POST:
            print(request.POST.getlist('geeks_field'))
        multivals = request.POST.getlist('geeks_field')
        print(multivals)
        form = GeeksForm(request.POST)
        if form.is_valid():
            print('good')
    demochc = ()
    for i in range(2,6):
        demochc += ((i, str(i)))
    context = {}
    print (demochc)
    form = GeeksForm()
    # form.fields['geeks_field'].choices = demochc 
    context['form'] =  form
    return render( request, "Invoice/home.html", context)

def add_so(request, pk=None):
    print("add INV")
    context = {}
    obj=None
    plname = None
    if pk:
        obj = get_object_or_404(Invoice.objects.select_related(), pk=pk)
        # obj = get_object_or_404(Invoice, pk=pk)
        plname = obj.CustomerRefFullName.PriceLevelRefFullName.Name
        # print(f"{obj.CustomerRefFullName.PriceLevelRefFullName.Name}")
    form = InvoiceForm(request.POST or None, instance=obj)
    # InvoiceItemLineFormset = modelformset_factory(InvoiceItemLine, form=InvoiceItemLineForm, extra=0) #cannot use extra >0 because the formset is zip with the qs below
    InvoiceItemLineFormset = inlineformset_factory(Invoice, InvoiceItemLine, form=InvoiceItemLineForm, extra=0) #cannot use extra >0 because the formset is zip with the qs below
    # InvoiceItemLineFormset = modelformset_factory(InvoiceItemLine, fields = ('ItemRefFullName', 'Desc', 'Quantity', 'UnitOfMeasure', 'Rate', 'Amount', 'Invoiced', 'LineIsManuallyClosed',), extra=1)
    # InvoiceItemLineFormset = modelformset_factory(InvoiceItemLine, fields = ('ItemRefFullName', 'Desc', 'Quantity', 'UnitOfMeasure', 'Rate', 'Amount', 'Invoiced', 'LineIsManuallyClosed',), extra=1)
    qs=None
    formset = InvoiceItemLineFormset(request.POST or None)
    if pk:
        print("got ID")
        qs = obj.invoiceitemline_set.all().order_by('id').select_related('ItemRefFullName')
        # formset = InvoiceItemLineFormset(request.POST or None, queryset=qs)
        formset = InvoiceItemLineFormset(request.POST or None, instance=obj)
    print(request.POST)
    # print(formset)
    # print(len(formset))
    # print(f"queryset={qs}")
    # print(f"queryset={qs[0].ItemRefFullName}")
    # qsItemList = list(x.ItemRefFullName for x in qs)
    # print(qsItemList)
    print(f'plname:{plname}')
    qsIn = Item.objects.filter(itempricelevel__PL__Name=plname).prefetch_related("itempricelevel").values('id', 'FullName','SalesDesc', 'SalesPrice', 'itempricelevel__Price')
    qsEx = Item.objects.exclude(itempricelevel__PL__Name=plname).prefetch_related("itempricelevel").values( "id", "FullName", "SalesDesc", "SalesPrice", "AlwaysNull")
    # print(qsIn)
    # print("qsEx")
    # print(qsEx)
    context['itemdatalist'] = qsIn.union(qsEx)

    context['object'] = obj
    context['qsformset'] = None
    if pk:
        context['qsformset'] = list(zip(qs, formset))
    if request.method == "POST":
        with transaction.atomic():
            if form.is_valid():
                # print(form.cleaned_data)
                # with transaction.atomic():
                # print(formset)
                if formset.is_valid():
                    for delform in formset.deleted_forms:
                        pass
                    totalamount=form.cleaned_data['TotalAmount']
                    print(totalamount, type(totalamount))
                    totalamountChildren=0
                    for fm in formset:
                        # print(fm)
                        print(fm['DELETE'].value())
                        if not fm['DELETE'].value() and 'Amount' in fm.cleaned_data:
                            # print(fm.cleaned_data['Amount'])
                            amount=fm.cleaned_data['Amount']
                            # print(amount)
                            print(fm['DELETE'].value())
                            totalamountChildren+=amount
                    print(totalamountChildren)
                    if totalamount==totalamountChildren:
                        print("correct total amount")
                    else:
                        print(f"not correct total amount:{totalamount} supposed={totalamountChildren}")
                    # form.cleaned_data['TotalAmount'] = totalamountChildren
                    parentobj = form.save(commit=False)
                    parentobj.TotalAmount = totalamountChildren
                    parentobj.save()
                    # print(parentobj)
                    print("formset valid")
                    instances = formset.save(commit=False)
                    for obj in formset.deleted_objects:
                        print("deelted object")
                        print(obj)
                        obj.delete()
                    for instance in instances:
                        # print(instance.ItemRefFullName)
                        # print(instance.pk)
                        # print(parentobj.id)
                        instance.Invoice = parentobj
                        instance.save()
                    context['message'] = "All Data Saved"
                    print("all formset saved")
                    print(parentobj.pk, type(parentobj.pk))
                    print(reverse('Invoice:edit_so', args=[parentobj.pk]))
                    messages.success(request, "All Data is Saved")
                    return redirect(reverse('Invoice:edit_so', args=[parentobj.pk]))
                else:
                    print("formset error")
                    print(formset.errors)
            else:
                print("form error")
                print(form.errors)
    context['form'] = form
    context['formset'] = formset
    return render(request, "Invoice/create-update.html", context=context)

# def add_so(request):
#     print("create SO")
#     context = {}
#     # obj = get_object_or_404(Invoice, pk=id)
#     obj=None
#     form = InvoiceForm(request.POST or None, )
#     InvoiceItemLineFormset = modelformset_factory(InvoiceItemLine, form=InvoiceItemLineForm, extra=1)
#     # qs = obj.invoiceitemline_set.all()
#     qs=None
#     formset = InvoiceItemLineFormset(request.POST or None, )
#     context['form'] = form
#     context['formset'] = formset
#     context['object'] = obj

#     if all([form.is_valid(),   formset.is_valid()]):
#         print(form.cleaned_data)
#         for form in formset:
#             print(form.clean_data)
#         context['message'] = "All Data saved"
#     return render(request, "Invoice/create-update.html", context=context)


def getpricelist_so(request, pk=None):
    print(f"getpricelist INV; pk={pk}")
    context = {}
    obj=None
    plname = None
    if pk:
        # obj = get_object_or_404(Invoice.objects.select_related(), pk=pk)
        obj = get_object_or_404(Customer.objects.select_related(), pk=pk)
        plname = obj.PriceLevelRefFullName.Name
        # print(f"{obj.CustomerRefFullName.PriceLevelRefFullName.Name}")
    # form = InvoiceForm(request.POST or None, instance=obj)
    # InvoiceItemLineFormset = inlineformset_factory(Invoice, InvoiceItemLine, form=InvoiceItemLineForm, extra=0) #cannot use extra >0 because the formset is zip with the qs below
    print(obj)
    qs=None
    # formset = InvoiceItemLineFormset(request.POST or None)
    # if pk:
    #     print("got ID")
    #     qs = obj.invoiceitemline_set.all().order_by('id').select_related('ItemRefFullName')
    #     # formset = InvoiceItemLineFormset(request.POST or None, queryset=qs)
    #     formset = InvoiceItemLineFormset(request.POST or None, instance=obj)
    print(request.GET)
    # print(len(formset))
    # print(f"queryset={qs}")
    # print(f"queryset={qs[0].ItemRefFullName}")
    # qsItemList = list(x.ItemRefFullName for x in qs)
    # print(qsItemList)
    print(f'plname1:{plname}')
    qsIn = Item.objects.filter(itempricelevel__PL__Name=plname).prefetch_related("itempricelevel").values('id', 'FullName','SalesDesc', 'SalesPrice', 'itempricelevel__Price')
    qsEx = Item.objects.exclude(itempricelevel__PL__Name=plname).prefetch_related("itempricelevel").values( "id", "FullName", "SalesDesc", "SalesPrice", "AlwaysNull")
    context['itemdatalist'] = qsIn.union(qsEx)
    serialized_q = json.dumps(list( context['itemdatalist']), cls=DjangoJSONEncoder)
    # p=json.loads(serialized_q)
    print(f'serialized_q:{serialized_q}') 
    serialized_obj = serializers.serialize('json', [ obj, ])
    context['obj'] = serialized_obj
    context['itemdatalist'] = serialized_q
    # serialized_q = serialized_q + serialized_obj
    # print(serialized_obj)
    data = json.dumps(context, indent=4, sort_keys=True, default=str)
    # print(data)
    # print(serialized_q)
    return JsonResponse(data, safe=False)

def edit_so(request):
    print("Edit SO")
    context = {}
    obj = get_object_or_404(Invoice, pk=id)
    form = InvoiceForm(request.POST or None, instance=obj)
    InvoiceItemLineFormset = modelformset_factory(InvoiceItemLine, form=InvoiceItemLineForm, extra=1)
    qs = obj.invoiceitemline_set.all()
    formset = InvoiceItemLineFormset(request.POST or None, isinstance=qs)
    context['form'] = form
    context['formset'] = formset
    context['object'] = obj

    if all([form.is_valid(),   formset.is_valid()]):
        print(form.cleaned_data)
        for form in formset:
            print(form.clean_data)
        context['message'] = "All Data saved"
    return render(request, "Invoice/create-update.html", context=context)

def delete_so(request):
    pass


