import datetime
import json
from datetime import timezone
import pandas as pd
from django.http import HttpResponse
from django.utils import timezone
from django.db.models import Q

from npayroll.settings import logger
from payrollservice.data.response.empadvancedetailsresponse import EmployeeadvancedetailsResponse
from payrollservice.models import Employeeadvancedetails, Payrolltran, Employeeadvancepayment
from payrollservice.service.auditservice import AudtiService
from payrollservice.service.empadvancepaymentservice import EmployeeadvancepaymentService
from payrollservice.service.empmonthlypaydeductionservice import Employeemonthlypay_deductionsService
from payrollservice.service.empmonthlypayinfoservice import EmployeemonthlypayService
from payrollservice.service.emppaystructureservice import EmployeePaystructureService
from payrollservice.service.payrolltranservice import PayrolltranService
from payrollservice.util.payrollutil import Activestatus, Advancetype, Advancestatus, ModifyStatus
from utilityservice.data.response.empmessage import Error
from utilityservice.data.response.nwisefinerror import NWisefinError
from utilityservice.data.response.nwisefinerrorconstants import ErrorMessage, ErrorDescription
from utilityservice.data.response.nwisefinlist import NWisefinList
from utilityservice.data.response.nwisefinpaginator import NWisefinPaginator
from utilityservice.data.response.nwisefinsuccess import NWisefinSuccess, SuccessMessage, SuccessStatus
from utilityservice.permissions.filter.commonpermission import ModulePermission
from utilityservice.permissions.util.dbutil import ModuleList, RoleList
from utilityservice.service.applicationconstants import ApplicationNamespace
from utilityservice.service.payroll_api_service import Payrollcommon_Apicall
from utilityservice.service.threadlocal import NWisefinThread

class EmployeeadvancedetailsService(NWisefinThread):
    def __init__(self, scope):
        super().__init__(scope)
        self._set_namespace(ApplicationNamespace.PAYROLL_SERVICE)

    def employeeadvance_create(self, data_obj):
        try:
            success_obj = NWisefinSuccess()
            if not data_obj.get_id() is None:
                obj = Employeeadvancedetails.objects.using(self._current_app_schema()).filter(id=data_obj.get_id()).update(employee_id=data_obj.get_employee_id(),
                                                                                                                           type = data_obj.get_type(),
                                                                                                                           from_date = data_obj.get_from_date(),
                                                                                                                           to_date = data_obj.get_to_date(),
                                                                                                                           advance_status = data_obj.get_advance_status(),
                                                                                                                           amount = data_obj.get_amount())
                obj = Employeeadvancedetails.objects.using(self._current_app_schema()).get(id=data_obj.get_id())
                success_obj.set_message(SuccessMessage.UPDATE_MESSAGE)

            else:
                obj = Employeeadvancedetails.objects.using(self._current_app_schema()).create(employee_id=data_obj.get_employee_id(),
                                                                                              type=data_obj.get_type(),
                                                                                              from_date=data_obj.get_from_date(),
                                                                                              to_date=data_obj.get_to_date(),
                                                                                              advance_status=data_obj.get_advance_status(),
                                                                                              amount=data_obj.get_amount())

                success_obj.set_message(SuccessMessage.CREATE_MESSAGE)
            return success_obj
        except Exception as excep:
            obj = NWisefinError()
            obj.set_code(ErrorMessage.INVALID_DATA)
            obj.set_description(str(excep))
            return obj

    def employeeadvance_summary(self, request,vys_page,user_id,admin):
        try:
        # if admin!='true':
        #     condition = Q(status=Activestatus.active,created_by=user_id)
        #     empadv_obj = Employeeadvancedetails.objects.using(self._current_app_schema()).filter(condition)[vys_page.get_offset():vys_page.get_query_limit()]
        #     emp_data = [i.employee_id for i in empadv_obj]
        #     apifunction = Payrollcommon_Apicall(self._scope())
        #     emp_name = apifunction.employee_detail_arr(emp_data)
        #     list_data = NWisefinList()
        #     for i in empadv_obj:
        #         data_resp = EmployeeadvancedetailsResponse()
        #         data_resp.set_id(i.id)
        #         data_resp.set_employee_val(i.employee_id,emp_name)
        #         data_resp.set_type(i.type)
        #         data_resp.set_from_date(i.from_date)
        #         data_resp.set_to_date(i.to_date)
        #         data_resp.set_advance_status(i.advance_status)
        #         # data_resp.set_amount(i.amount)
        #         list_data.append(data_resp)
        #     vpage = NWisefinPaginator(empadv_obj, vys_page.get_index(), 10)
        #     list_data.set_pagination(vpage)
        #     return list_data
        # else:
            apifunction = Payrollcommon_Apicall(self._scope())
            module = ModuleList.Employee_Payroll
            hr_rights = apifunction.employee_role_check(user_id, module, None, None)
            condition = Q(status=Activestatus.active)
            condition1 = ~Q(employee_id=user_id)
            employee = request.GET.get('employee')
            advance_status = request.GET.get('advance_status')
            if employee != None and employee != "":
                emp_list = apifunction.emp_arr_function(employee)
                condition &= Q(employee_id__in=emp_list)
            if advance_status != None and advance_status != "":
                condition &= Q(advance_status=advance_status)
            if hr_rights == 0 or admin!='True':
                empadv_obj = Employeeadvancedetails.objects.using(self._current_app_schema()).filter(condition, employee_id=user_id).order_by('-id')[vys_page.get_offset():vys_page.get_query_limit()]
            else:
                payroll_tran_data = list(Payrolltran.objects.using(self._current_app_schema()).filter(tran_to=user_id,status=Activestatus.active).values_list('ref_id',flat=True))
                empadv_obj = Employeeadvancedetails.objects.using(self._current_app_schema()).filter(condition, condition1,id__in=payroll_tran_data).order_by('-id')[vys_page.get_offset():vys_page.get_query_limit()]
            list_data = NWisefinList()
            if empadv_obj.count() > 0:
                emp_data = [i.employee_id for i in empadv_obj]
                apifunction = Payrollcommon_Apicall(self._scope())
                emp_name = apifunction.employee_detail_arr(emp_data)
                for i in empadv_obj:
                    data_resp = EmployeeadvancedetailsResponse()
                    data_resp.set_id(i.id)
                    data_resp.set_employee_val(i.employee_id, emp_name)
                    data_resp.set_type(i.type)
                    data_resp.set_from_date(i.from_date)
                    data_resp.set_to_date(i.to_date)
                    data_resp.set_created_by(i.created_by)
                    data_resp.set_advance_status(i.advance_status)
                    data_resp.set_advance_amount(i.payable_amount)
                    data_resp.set_emi_amount(i.emi_amount)
                    data_resp.set_reason(i.reason)
                    data_resp.set_code(i.code)
                    list_data.append(data_resp)
                vpage = NWisefinPaginator(empadv_obj, vys_page.get_index(), 10)
                list_data.set_pagination(vpage)
            else:
                vpage = NWisefinPaginator([], vys_page.get_index(), 10)
                list_data.set_pagination(vpage)
            return list_data
        except Exception as excep:
            obj = NWisefinError()
            obj.set_code(ErrorMessage.INVALID_DATA)
            obj.set_description(str(excep))
            return obj


    def employeeadvance_get(self, id_val):
        try:
            obj = Employeeadvancedetails.objects.using(self._current_app_schema()).get(status=Activestatus.active,id=id_val)
            data_resp = EmployeeadvancedetailsResponse()
            data_resp.set_id(obj.id)
            apifunction = Payrollcommon_Apicall(self._scope())
            emp_obj = apifunction.emp_info(obj.employee_id)
            if not emp_obj:
                error_obj = NWisefinError()
                error_obj.set_code(ErrorMessage.INVALID_DATA)
                error_obj.set_description('invalid employee request')
                return error_obj
            data_resp.name = emp_obj.get('full_name')
            advance_obj = EmployeePaystructureService(self._scope()).advance_gross_pay(obj.employee_id)
            if advance_obj == None:
                data_resp.gross_pay = str(0.00)
                data_resp.take_home = str(0.00)
            else:
                data_resp.gross_pay = str(advance_obj['gross_pay'])
                data_resp.take_home = str(advance_obj['take_home'])
            deduct_obj = Employeemonthlypay_deductionsService(self._scope()).advance_deduct_data(obj.employee_id, obj.from_date)
            if deduct_obj['amount__sum'] == None:
                data_resp.total_deductions = str(0.00)
            else:
                data_resp.total_deductions = str(deduct_obj['amount__sum'])
            # balance_oldadvance = EmployeeadvancepaymentService(self._scope()).balance_old_advance(obj.id)
            # if balance_oldadvance == None:
            #     data_resp.balance_oldadvance = str(0.00)
            # else:
            #     data_resp.balance_oldadvance = str(balance_oldadvance['balance_amount'])
            # emi_oldadvance = EmployeeadvancepaymentService(self._scope()).emi_old_advance(obj.id)
            # if emi_oldadvance == None:
            #     data_resp.emi_oldadvance = str(0.00)
            # else:
            #     data_resp.emi_oldadvance = str(emi_oldadvance['paid_amount'])
            # new old advance
            oldadvance=self.advance_balance_old_emi(obj.employee_id)
            if oldadvance == None:
                data_resp.balance_oldadvance = 0.00
                data_resp.emi_oldadvance = 0.00
            else:
                data_resp.balance_oldadvance = oldadvance.balance_oldadvance
                data_resp.emi_oldadvance = oldadvance.emi_oldadvance
            # data_resp.name = emp_obj.full_name
            data_resp.set_type(obj.type)
            data_resp.set_from_date(obj.from_date)
            data_resp.set_to_date(obj.to_date)
            data_resp.set_advance_status(obj.advance_status)
            data_resp.set_actual_amount(obj.actual_amount)
            data_resp.set_payable_amount(obj.payable_amount)
            data_resp.set_emi_amount(obj.emi_amount)
            data_resp.set_reason(obj.reason)
            data_resp.set_created_by(obj.created_by)
            # payrolltran
            payroll_data = PayrolltranService(self._scope()).advance_level_get(obj.id, obj.advance_status)
            payroll_data = next(iter(payroll_data), None)
            if payroll_data and payroll_data.tran_to:
                data_resp.tran_id = payroll_data.id if payroll_data else None
                emp_obj = apifunction.emp_info(payroll_data.tran_to)
                data_resp.to_employee_id = emp_obj
            else:
                data_resp.to_employee_id = None
            data_resp.remarks = payroll_data.remarks if payroll_data and payroll_data.remarks else None

            # data_resp.set_amount(obj.amount)
            return data_resp

        except:
            error_obj = NWisefinError()
            error_obj.set_code(ErrorMessage.INVALID_ID)
            error_obj.set_description(ErrorDescription.INVALID_DATA)
            return error_obj

    def advance_balance_old_emi(self,employee_id):
        try:
            obj = Employeeadvancedetails.objects.using(self._current_app_schema()).filter(status=Activestatus.active,employee_id=employee_id,advance_status=Advancestatus.open)
            if obj.count() > 0:
                data_resp = EmployeeadvancedetailsResponse()
                id_data = [i.id for i in obj]
                balance_oldadvance = EmployeeadvancepaymentService(self._scope()).balance_old_advance1(id_data)
                if balance_oldadvance.balance_amount == None:
                    data_resp.balance_oldadvance = str(0.00)
                else:
                    data_resp.balance_oldadvance = str(balance_oldadvance.balance_amount)
                if balance_oldadvance.paid_amount == None:
                    data_resp.emi_oldadvance = str(0.00)
                else:
                    data_resp.emi_oldadvance = str(balance_oldadvance.paid_amount)
                return data_resp
        except Exception as excep:
            obj = Error()
            obj.set_code(ErrorMessage.INVALID_DATA)
            obj.set_description(str(excep))
            return obj


    def create_employeedetails(self, data_obj, user_id,  from_date, to_date):
        error_obj = NWisefinError()
        success_obj = NWisefinSuccess()
        emp_adv = list(Employeeadvancedetails.objects.using(self._current_app_schema()).filter(id=data_obj.get_id()))
        if len(emp_adv) > 0 and emp_adv[0].created_by == user_id or emp_adv == []:
            if not data_obj.get_id() is None:
                obj = Employeeadvancedetails.objects.using(self._current_app_schema()).filter(
                    id=data_obj.get_id()).update(
                    employee_id=user_id,
                    type=data_obj.get_type(),
                    from_date=from_date,
                    to_date=to_date,
                    advance_status=data_obj.get_advance_status(),
                    actual_amount=data_obj.get_actual_amount(),
                    payable_amount=data_obj.get_actual_amount(),
                    # payable_amount=data_obj.get_payable_amount(),
                    reason=data_obj.get_reason(),
                    emi_amount=data_obj.get_emi_amount(),
                    updated_by=user_id,
                    updated_date=timezone.now())
                obj = Employeeadvancedetails.objects.using(self._current_app_schema()).get(id=data_obj.get_id())
                audit_insert_data = AudtiService(self._scope()).audit_function(obj, obj.id,
                                                                               obj.employee_id,
                                                                               Advancetype.employeeadvance_details,
                                                                               ModifyStatus.UPDATE)

                if data_obj.get_advance_status() == Advancestatus.draft:
                    tran_to = data_obj.get_to_employee_id()
                    obj_data = Payrolltran.objects.using(self._current_app_schema()).filter(id=data_obj.get_tran_id()).update(ref_id=obj.id,
                                                                                            remarks=data_obj.get_remarks(),
                                                                                            ref_type=Advancetype.employeeadvance_details,
                                                                                            tran_from=user_id,
                                                                                            tran_to=tran_to,
                                                                                            from_date=datetime.datetime.now(),
                                                                                            tran_status=obj.advance_status)

                    obj_data = Payrolltran.objects.using(self._current_app_schema()).get(id=data_obj.get_tran_id())

                if data_obj.get_advance_status() == Advancestatus.move_to_checker:
                    tran_to = data_obj.get_to_employee_id()
                    obj_data = Payrolltran.objects.using(self._current_app_schema()).create(ref_id=obj.id,
                                                                                            remarks=data_obj.get_remarks(),
                                                                                            ref_type=Advancetype.employeeadvance_details,
                                                                                            tran_from=user_id,
                                                                                            tran_to=tran_to,
                                                                                            from_date=datetime.datetime.now(),
                                                                                            tran_status=obj.advance_status)
                success_obj.set_status(SuccessStatus.SUCCESS)
                success_obj.set_message(SuccessMessage.UPDATE_MESSAGE)
            # success_obj.Data = obj

            else:
                # advance_pay = Employeeadvancepayment.objects.using(self._current_app_schema()).filter(condition,status=Activestatus.active, advance__employee_id=user_id,advance__from_date__month__lte=from_date.month, advance__to_date__month__gte=to_date.month,advance__from_date__year__lte=from_date.year, advance__to_date__year__gte=to_date.year,advance__advance_status__in=[1,8,9,10,11]).values_list('advance__employee_id', flat=True)
                # advance_pay = Employeeadvancedetails.objects.using(self._current_app_schema()).filter(status=Activestatus.active,employee_id=user_id,from_date__month__lte=from_date.month,from_date__year__lte=from_date.year,to_date__year__gte=to_date.year,advance_status__in=[1,8,9,10,11]).values_list('employee_id', flat=True)
                # advance_details = Employeeadvancedetails.objects.using(self._current_app_schema()).filter(status=Activestatus.active,employee_id=user_id,advance_status__in=[1,8,9,10,11])
                # if advance_details.count() > 0:
                #     for advance_details_data in advance_details:
                #         from_month = advance_details_data.from_date.month
                #         to_month = advance_details_data.to_date.month
                #         from_year = advance_details_data.from_date.year
                #         to_year =  advance_details_data.to_date.year
                #         if from_date.month <= from_month and to_date.month >= to_month and from_date.year <= from_year and to_date.year >= to_year:
                #             advance_pay = advance_details.filter(id=advance_details_data.id).values_list('employee_id', flat=True)
                #             arr1 = list(set(advance_pay))
                #             if len(arr1) > 0:
                #                 advance_pay1 = Employeeadvancepayment.objects.using(self._current_app_schema()).filter(balance_amount=0.00,status=Activestatus.active).values_list('advance__employee_id', flat=True)
                #                 arr1 = list(set(advance_pay1))
                #                 if len(arr1) > 0:
                #                     print('PLEASE CLOSE ALREADY EXISTS IN ADVANCE')
                #         success_obj = NWisefinSuccess()
                #         success_obj.set_status("INVALID EMPLOYEE CODE")
                #         success_obj.set_message("PLEASE CLOSE ALREADY EXISTS IN ADVANCE")
                #     return success_obj
                # else:
                    if (data_obj.get_advance_status() == Advancestatus.move_to_checker and data_obj.get_advance_id()=="" or data_obj.get_advance_id()==None) or (data_obj.get_advance_status() == Advancestatus.draft and data_obj.get_advance_id()== "" or data_obj.get_advance_id()==None):
                        tran_to = data_obj.get_to_employee_id()
                    else:
                        tran_to = user_id
                    obj = Employeeadvancedetails.objects.using(self._current_app_schema()).create(
                        employee_id=user_id,
                        type=data_obj.get_type(),
                        from_date=from_date,
                        to_date=to_date,
                        advance_status=data_obj.get_advance_status(),
                        actual_amount=data_obj.get_actual_amount(),
                        # payable_amount=data_obj.get_payable_amount(),
                        payable_amount=data_obj.get_actual_amount(),
                        reason=data_obj.get_reason(),
                        emi_amount=data_obj.get_emi_amount(), created_by=user_id)

                    code = 'ADVANCEPAYSLIP0' + str(obj.id).zfill(5)
                    obj.code = code
                    obj.save()

                    obj_data = Payrolltran.objects.using(self._current_app_schema()).create(ref_id=obj.id,
                                                                                            remarks=data_obj.get_remarks(),
                                                                                            ref_type=Advancetype.employeeadvance_details,
                                                                                            tran_from=user_id,
                                                                                            tran_to=tran_to,
                                                                                            from_date=datetime.datetime.now(),
                                                                                            tran_status=obj.advance_status
                                                                                            )
                    audit_insert_data = AudtiService(self._scope()).audit_function(obj, obj.id,obj.employee_id,Advancetype.employeeadvance_details,ModifyStatus.CREATE)
                    success_obj.set_status(SuccessStatus.SUCCESS)
                    success_obj.set_message(SuccessMessage.CREATE_MESSAGE)
                    success_obj.id = obj.id
            return success_obj
        else:
            error_obj.set_message(ErrorMessage.ERROR)
            error_obj.set_description('maker can only update')
        return error_obj


    def employeeadvance_details_summary(self, vys_page):
        condition = Q(status=Activestatus.active)
        empadv_obj = Employeeadvancedetails.objects.using(self._current_app_schema()).filter(condition)[vys_page.get_offset():vys_page.get_query_limit()]
        employee_arr = [i.employee_id for i in empadv_obj]
        apifunction = Payrollcommon_Apicall(self._scope())
        employee_details = apifunction.employee_get_value(employee_arr)
        list_data = NWisefinList()
        for i in empadv_obj:
            data_resp = EmployeeadvancedetailsResponse()
            data_resp.set_id(i.id)
            data_resp.set_employee_val(i.employee_id, employee_details)
            data_resp.set_actual_amount(i.actual_amount)
            data_resp.set_payable_amount(i.payable_amount)
            data_resp.set_emi_amount(i.emi_amount)
            data_resp.set_advance_status(i.advance_status)
            list_data.append(data_resp)
        vpage = NWisefinPaginator(empadv_obj, vys_page.get_index(), 10)
        list_data.set_pagination(vpage)
        return list_data


    def employeeadvance_details_get(self, id_val):
        try:
            obj = Employeeadvancedetails.objects.using(self._current_app_schema()).get(status=Activestatus.active,id=id_val)
            apifunction = Payrollcommon_Apicall(self._scope())
            emp_data = apifunction.employee_get_value([obj.employee_id])
            data_resp = EmployeeadvancedetailsResponse()
            data_resp.set_id(obj.id)
            data_resp.set_employee_val(obj.employee_id, emp_data)
            data_resp.set_actual_amount(obj.actual_amount)
            data_resp.set_payable_amount(obj.payable_amount)
            data_resp.set_emi_amount(obj.emi_amount)
            return data_resp
        except:
            error_obj = NWisefinError()
            error_obj.set_code(ErrorMessage.INVALID_ID)
            error_obj.set_description(ErrorDescription.INVALID_DATA)
            return error_obj

    def employee_advance_inactive(self, id_val):
        obj = Employeeadvancedetails.objects.using(self._current_app_schema()).filter(id=id_val).update(status=Activestatus.inactive)
        if obj == 0:
            error_obj = NWisefinError()
            error_obj.set_code(ErrorMessage.INVALID_ID)
            error_obj.set_description(ErrorDescription.INVALID)
            return error_obj
        else:
            success_obj = NWisefinSuccess()
            success_obj.set_status(SuccessStatus.SUCCESS)
            success_obj.set_message(SuccessMessage.DELETE_MESSAGE)
            return success_obj


    def employeeadvance_download(self,request,vys_page, user_id, action):
        apifunction = Payrollcommon_Apicall(self._scope())
        module = ModuleList.Employee_Payroll
        hr_rights = apifunction.employee_role_check(user_id, module, None, None)
        condition = Q(status=Activestatus.active)
        query = request.GET.get('employee')
        approved_id = request.GET.get('approved')
        if query != None and query != "":
            emp_list = apifunction.emp_arr_function(query)
            condition &= Q(employee_id__in=emp_list)
        if hr_rights == 0:
            empadv_obj = Employeeadvancedetails.objects.using(self._current_app_schema()).filter(condition,
                                                                    employee_id=user_id)[
                         vys_page.get_offset():vys_page.get_query_limit()]
        else:
            empadv_obj = Employeeadvancedetails.objects.using(self._current_app_schema()).filter(condition,advance_status=approved_id)[
                         vys_page.get_offset():vys_page.get_query_limit()]

        list_data = NWisefinList()
        if hr_rights in [0, 1, 2] and int(action) in [1, 2]:
            if empadv_obj.count() > 0:
                emp_data = [i.employee_id for i in empadv_obj]
                emp_advance = [i.id for i in empadv_obj]
                apifunction = Payrollcommon_Apicall(self._scope())
                emp_name = apifunction.employee_detail_arr(emp_data)
                emp_amount = EmployeeadvancepaymentService(self._scope()).employee_amount_arr(emp_advance)
                for i in empadv_obj:
                    data_resp = EmployeeadvancedetailsResponse()
                    data_resp.set_id(i.id)
                    data_resp.set_employee_val(i.employee_id, emp_name)
                    data_resp.set_employee_amount(i.id, emp_amount)
                    data_resp.set_count_payment(self.payment_count(i.id))
                    data_resp.set_type(i.type)
                    data_resp.set_from_date(i.from_date)
                    data_resp.set_to_date(i.to_date)
                    data_resp.set_created_by(i.created_by)
                    data_resp.set_advance_status(i.advance_status)
                    data_resp.set_actual_amount(i.actual_amount)
                    data_resp.set_emi_amount(i.emi_amount)
                    # data_resp.set_amount(i.amount)
                    list_data.append(data_resp)
                    vpage = NWisefinPaginator(empadv_obj, vys_page.get_index(), 10)
                    list_data.set_pagination(vpage)
            else:
                vpage = NWisefinPaginator([], vys_page.get_index(), 10)
                list_data.set_pagination(vpage)
            if hr_rights in [1,2,0] and int(action) == 1:
                return list_data.get()

        if hr_rights == 1 and int(action) == 2:
            page_data = list_data.data
            df = [json.loads(page_data[i].get()) for i in range(0, len(page_data))]
            page_df = pd.DataFrame.from_records(df)
            page_df['Code'] = page_df['employee_data'].apply(lambda x: x['employee_no'])
            page_df['Employee Name'] = page_df['employee_data'].apply(lambda x: x['name'])
            page_df['Approval'] = page_df['advance_status'].apply(lambda x: x['name'])
            page_df['Paid Amount'] = page_df['employee_amount'].apply(lambda x: x['paid_amount'] if x is not None and 'paid_amount' in x else 0.0)
            page_df['Remaining Amount'] = page_df['employee_amount'].apply(lambda x: x['balance_amount'] if x is not None and 'balance_amount' in x else 0.0)
            page_df['Paid Date'] = page_df['employee_amount'].apply(lambda x: x['paid_date']if (x is not None and 'paid_date' in x) else None)
            # page_df["No Of Installment"] = 0
            page_df.rename(columns={'from_date' : 'From Date','to_date' : 'To Date',"actual_amount" : "Amount","emi_amount" : "EMI Amount", "No_Of_Installment" : "No Of Installment"}, inplace=True)
            page_df["Employee Name"] = page_df["Employee Name"].str.upper()
            page_df["Paid Date"] = pd.to_datetime(page_df["Paid Date"])
            # page_df['Paid Date'] = page_df['Paid Date'].fillna('None')
            page_df["From Date"] = pd.to_datetime(page_df["From Date"])
            page_df["To Date"] = pd.to_datetime(page_df["To Date"])
            page_df["From Date"] = page_df["From Date"].dt.strftime('%b/%y').str.replace('/', '-')
            page_df["To Date"] = page_df["To Date"].dt.strftime('%b/%y').str.replace('/', '-')
            page_df["Paid Date"] = page_df["Paid Date"].apply(lambda x: x.strftime('%b/%y') if x != 'None' else 'None').str.replace('/', '-')
            page_download_df = page_df[['Code', 'Employee Name', 'From Date', 'To Date', 'Approval',"Amount","EMI Amount",
                                        "No Of Installment",'Paid Date','Paid Amount','Remaining Amount']]
            excel = 'application/vnd.ms-excel'
            response = HttpResponse(content_type=excel)
            response['Content-Disposition'] = 'attachment; filename="vpage.xlsx"'
            writer = pd.ExcelWriter(response, engine='xlsxwriter')
            page_download_df.index.name = 'S.NO'
            final_df = page_download_df.reset_index()
            final_df['S.NO'] = final_df['S.NO'] + 1
            final_df.to_excel(writer, index=False)
            writer.close()
            return HttpResponse(response)

    def payment_count(self, employee_id):
        obj = Employeeadvancepayment.objects.using(self._current_app_schema()).filter(advance_id=employee_id)
        data = len(obj)
        return data



    def update_advancestatus(self, user_id,advance_obj):
        try:
            from datetime import datetime
            condition = Q(status=Activestatus.active)
            # for i in struct_obj:
            update_status = Employeeadvancedetails.objects.using(self._current_app_schema()).filter(condition, id__in=advance_obj['id']).update(advance_status=Advancestatus.paid,amount_reciveddate=datetime.now(),remarks=advance_obj['remarks'],updated_by=user_id,updated_date=datetime.now())
            if update_status == 0:
                error_obj = NWisefinError()
                error_obj.set_code(ErrorMessage.INVALID_ID)
                error_obj.set_description(ErrorDescription.INVALID)
                return error_obj
            else:
                success_obj = NWisefinSuccess()
                success_obj.set_status(SuccessStatus.SUCCESS)
                success_obj.set_message(SuccessMessage.UPDATE_MESSAGE)
            return success_obj
        except Exception as excep:
            obj = NWisefinError()
            obj.set_code(ErrorMessage.INVALID_DATA)
            obj.set_description(str(excep))
            return obj

    def excel_update_advancestatus(self, user_id,advance_obj):
        try:
            update_status = None
            from datetime import datetime
            condition = Q(status=Activestatus.active)
            condition1 = ~Q(advance_status=Advancestatus.paid)
            for advance in advance_obj:
                employee = Payrollcommon_Apicall(self._scope()).emp_code(advance['EMPLOYEE_CODE'])
                update_status = Employeeadvancedetails.objects.using(self._current_app_schema()).filter(condition,condition1, employee_id=employee.get('id')).update(advance_status=Advancestatus.paid,amount_reciveddate=datetime.now(),remarks=advance['REMARKS'],updated_by=user_id,updated_date=datetime.now())
            if update_status == 0:
                error_obj = NWisefinError()
                error_obj.set_code(ErrorMessage.INVALID_ID)
                error_obj.set_description(ErrorDescription.INVALID)
                return error_obj
            else:
                success_obj = NWisefinSuccess()
                success_obj.set_status(SuccessStatus.SUCCESS)
                success_obj.set_message(SuccessMessage.UPDATE_MESSAGE)
            return success_obj
        except Exception as excep:
            obj = NWisefinError()
            obj.set_code(ErrorMessage.INVALID_DATA)
            obj.set_description(str(excep))
            logger.info('Bank Based Employee Advance Paid Status Update', str(excep))
            return obj


    def advancesummary(self,request,user_id,admin,vys_page):
        try:
            apifunction = Payrollcommon_Apicall(self._scope())
            module = ModuleList.Employee_Payroll
            hr_rights = apifunction.employee_role_check(user_id, module, None, None)
            condition = Q(status=Activestatus.active)
            employee = request.GET.get('employee')
            advance_status = request.GET.get('advance_status')
            if employee != None and employee != "":
                emp_list = apifunction.emp_arr_function(employee)
                condition &= Q(employee_id__in=emp_list)
            if advance_status != None and advance_status != "":
                condition &= Q(advance_status=advance_status)
            if hr_rights == 1:
                empadv_obj = Employeeadvancedetails.objects.using(self._current_app_schema()).filter(condition).order_by('-id')[vys_page.get_offset():vys_page.get_query_limit()]
            else:
                empadv_obj = Employeeadvancedetails.objects.using(self._current_app_schema()).filter(condition, employee_id=user_id).order_by(
                    '-id')[vys_page.get_offset():vys_page.get_query_limit()]
            list_data = NWisefinList()
            if empadv_obj.count() > 0:
                emp_data = [i.employee_id for i in empadv_obj]
                apifunction = Payrollcommon_Apicall(self._scope())
                emp_name = apifunction.employee_detail_arr(emp_data)
                dept_name = apifunction.emp_department(emp_data)
                for i in empadv_obj:
                    data_resp = EmployeeadvancedetailsResponse()
                    data_resp.set_id(i.id)
                    data_resp.set_employee_val(i.employee_id, emp_name)
                    data_resp.set_department_val(i.employee_id,dept_name)
                    # data_resp.set_emi_amount(i.emi_amount)
                    # request_date
                    import datetime
                    from_date = datetime.datetime.strptime(str(i.from_date), '%Y-%m-%d')
                    # Calculate the previous month
                    if from_date.month == 1:
                        previous_month = 12
                        previous_year = from_date.year - 1
                    else:
                        previous_month = from_date.month - 1
                        previous_year = from_date.year
                    request_date= (datetime.date(previous_year, previous_month, 1).strftime('%B %Y'))
                    data_resp.request_date = str(request_date)
                    data_resp.request_amount = str(i.payable_amount)
                    if i.updated_by != None:
                        emp_obj = apifunction.emp_info(i.updated_by)
                        data_resp.approved_by = f"({emp_obj.get('code') or ''}) {emp_obj.get('full_name') or ''}" if emp_obj else None
                    else:
                        data_resp.approved_by = None
                    pay_history = EmployeeadvancepaymentService(self._scope()).employeeadvance_payment_history(i.id)
                    if len(pay_history.data) > 0:
                        paidamount = [int(float(j.paid_amount))for j in pay_history.data]
                        data_resp.paid_date = str(pay_history.data[-1].paid_date)
                        data_resp.emi_paid = str(sum(paidamount))
                        data_resp.emi_balance = str(pay_history.data[-1].balance_amount)
                    else:
                        data_resp.paid_date = None
                        data_resp.emi_paid = None
                        data_resp.emi_balance = None
                    data_resp.set_advance_status(i.advance_status)
                    data_resp.set_emi_amount(i.emi_amount)
                    list_data.append(data_resp)
                vpage = NWisefinPaginator(empadv_obj, vys_page.get_index(), 10)
                list_data.set_pagination(vpage)
            else:
                vpage = NWisefinPaginator([], vys_page.get_index(), 10)
                list_data.set_pagination(vpage)
            return list_data
        except Exception as excep:
            obj = NWisefinError()
            obj.set_code(ErrorMessage.INVALID_DATA)
            obj.set_description(str(excep))
            return obj

    def update_advanceforceclose(self,data_json, user_id):
        error_obj = NWisefinError()
        from datetime import datetime
        advan_detail = Employeeadvancedetails.objects.using(self._current_app_schema()).filter(status=Activestatus.active,id=data_json['id'])
        advan_payment = EmployeeadvancepaymentService(self._scope()).emi_close(data_json, user_id)
        if advan_payment.code == 200:
            advandetails_update = advan_detail.update(advance_status=Advancestatus.force_closed,updated_by=user_id,updated_date=datetime.now())
            if advandetails_update == 0:
                error_obj.set_code(ErrorMessage.INVALID_ID)
                error_obj.set_description(ErrorDescription.INVALID)
                return error_obj
            else:
                success_obj = NWisefinSuccess()
                success_obj.set_status(SuccessStatus.SUCCESS)
                success_obj.set_message(SuccessMessage.UPDATE_MESSAGE)
                return success_obj
        else:
            error_obj.set_code(ErrorMessage.INVALID_ID)
            error_obj.set_description(ErrorDescription.INVALID)
            return error_obj
