# coding: utf8
from __future__ import unicode_literals
from datetime import timedelta
import logging
from backoffice.models import *
from backoffice.helpers import getEventDateToParisTimeZone, getFreeWallet, getWalletToUseOrWait, hasEventEnded, sendEmail,sendInvoice
from web3 import Web3
from web3.middleware import geth_poa_middleware
from tixsell import settings
from tixsell.settings import ORGANISER_FACTORY_ABI, TICKET_ABI
from tixsell.celery import app
from tixsell.settings import wallet_pool
import time
import sendgrid
from toolz.itertoolz import unique
import json
from django.utils import timezone
from api.content import decrypt_private_key_AES256, encrypt
from backoffice.helpers import transactionLogger,releaseWallet
import stripe
logger = logging.getLogger('django')
 

def taskCreateOrganiserContract(task):
    pass
def taskOffrirTickets(task):
    #from alchemy import Alchemy, Network
    import json
     
    try:
        logger.info("===offrir tickets")
        logger.info(task)
        logger.info(task.metadata)
        metadata = json.loads(task.metadata)
        refInvitation = metadata["refInvitation"]
        
        logger.info("===offrir tickets pour refInvitation %s"%(refInvitation))
        invitation = Invitation.objects.get(id=refInvitation)
        if invitation.burned:
            logger.info("===offrir tickets pour refInvitation %s burned"%refInvitation)
            return
        userToSend = User.objects.get(email=invitation.toUser)
        userFrom = invitation.fromUser
        
       
        web3 = Web3(Web3.HTTPProvider(settings.CONTRACT_NODE_URL))
        DEBUG = os.getenv("DEBUG")
        CHAIN_ID = settings.CHAIN_ID
        if DEBUG:
            web3.middleware_onion.inject(geth_poa_middleware, layer=0)
          
        if userFrom.generatedWallet==False:
            # pas besoin de payer fess car appartient à SellTix
            envoiDone = True
            PRIVATE_KEY_TO_USE = settings.SELLTIX_WALLET_PRIVATE_KEY4
            ADRESS_TO_USE = settings.SELLTIX_WALLET4
        else:
            # On envoi un peu de matic pour payer les gas fees
            maticToSendAmount = "0.1"
            from backoffice.helpers import sendMatic
            envoiDone = sendMatic(userFrom.walletAddress,maticToSendAmount)
            userFrom.maticSent = True
            userFrom.save()
            # decrypt wallet from user who invits and transfert to the new wallet
            logger.info("===MAtic transféré on decrypte le wallet")
            ADRESS_TO_USE = userFrom.walletAddress
            thePinCodeToDecrypt = decrypt_private_key_AES256(userFrom.pinCode,os.getenv("SECRET_PIN_KEY"))
            realCodePin = 9999 - int(thePinCodeToDecrypt)
            PRIVATE_KEY_TO_USE = decrypt_private_key_AES256(userFrom.privateKey,str(realCodePin))
        
        if envoiDone: 
            # Initialize the address calling the fOunctions/signing transactions
            # Initialize contract ABI and address
            #Need to wait for wallet   and then locked it while processing 
            logger.info("===Wallet Address : "+ADRESS_TO_USE)
            checkedWalletAddress = web3.to_checksum_address(ADRESS_TO_USE) 
            checkedToWalletAddress = web3.to_checksum_address(userToSend.walletAddress)
            # Create smart contract instance
            checkedTicketAddress = web3.to_checksum_address(invitation.refTicket.refTicketType.refEvent.ticketContract)
            logger.info("===Contract Address : "+checkedTicketAddress)
            contract = web3.eth.contract(address=checkedTicketAddress, abi=TICKET_ABI)
            # : call 
            nonce = web3.eth.get_transaction_count(checkedWalletAddress,"latest")
            logger.info("===nonce : "+str(nonce))
            # call transfert METHOD 
            transaction = contract.functions.transferFrom(checkedWalletAddress,checkedToWalletAddress,int(invitation.refTicket.ticketId)).build_transaction({
                    'from': checkedWalletAddress,
                    'nonce': nonce,
                    'gasPrice': web3.to_wei('40', 'gwei'),
                    'gas': '0'
                }) 
            gas = web3.eth.estimate_gas(transaction)
            transaction.update({'gas': gas})
                
            signed_txn = web3.eth.account.sign_transaction(transaction, private_key=PRIVATE_KEY_TO_USE)
            receipt = web3.eth.send_raw_transaction(signed_txn.rawTransaction)
            logger.info('preview trx hash (trx could be in pending status)', web3.to_hex(web3.keccak(signed_txn.rawTransaction)))
            # blocking: Wait for the transaction to be mined, and get the transaction receipt
            resultTx = web3.eth.wait_for_transaction_receipt(receipt)
            logger.info('receipt with confirmed trx hash (after trx executed)',resultTx )
            status = resultTx["status"]
            transactionLogger(nonce,resultTx,'transferFrom',status,checkedToWalletAddress)
            if status == 1:
                invitation.burned=True
                invitation.save()
                #Ticket assigne au nouveal utilisateur et remet les compteurs à zero
                invitation.refTicket.refUser = userToSend
                invitation.refTicket.hasBeenOffered=False
                invitation.refTicket.transferedToSellTix=False
                invitation.refTicket.save()
                #Change Ticket user will be done by blockchain events 
                task.status=2
                task.save()
                logger.info("===Ticket transféré")
            else:
                #Ticket selltix non transféré ! 
                message="Billet invitation<b>%s</b> transfert échoué !"%(str(invitation.pk))
                sendEmail("csurbier@idevotion.fr","[SellTix] Ticket offert transfert blockchain échoué",message)
                logger.info("Error when transferting ticket")
                logger.info(resultTx)
                task.status=3
                task.save()
        else:
            message="Billet invitation<b>%s</b> transfert échoué "%(str(invitation.pk))
            sendEmail("csurbier@idevotion.fr","[SellTix] Ticket offert  échoué",message)
            logger.info(resultTx)
            task.status=3
            task.save()
    except Exception as e:
        logger.info(e)
        message="Billet invitation<b>%s</b> exception survenue"%(str(e))
        sendEmail("csurbier@idevotion.fr","[SellTix] Ticket offert  échoué",message)
        task.status=3
        task.save()
      
def taskCheckTickets(task):
    #from alchemy import Alchemy, Network
    import requests,json
    try:
        logger.info("===check tickets")
        logger.info(task)
        logger.info(task.metadata)
        metadata = json.loads(task.metadata)
        checkedWalletAddress = metadata["walletAddress"]
        logger.info("===check tickets pour wallet %s"%checkedWalletAddress)
        url = settings.ALCHEMY_API_ENDPOINT_NFT+settings.ALCHEMY_ACCESS_KEY+"/getNFTsForOwner?owner="+checkedWalletAddress+"&withMetadata=true&pageSize=100"
        headers = {"accept": "application/json"}
        logger.info(url)
        response = requests.get(url, headers=headers)
        if response.text:
            try:
                user = User.objects.get(pk=metadata["refUser"])
            except Exception as e:
                user = None
                task.status=2
                task.save()
                logger.info("===Pas de user SellTix")
            if user:
                data = json.loads(response.text)
                #logger.info(data)
                logger.info("===check NFTS pour wallet %s"%checkedWalletAddress)
                logger.info("Possede %d NFTs"%data["totalCount"])
                for nft in data["ownedNfts"]:
                    #logger.info(nft)
                    contract = nft["contract"]
                    if " - SellTix.live content" in contract["name"]:
                        logger.info("====NFT SellTix content Name %s"%contract["name"])
                        logger.info("====NFT SellTix content Address %s"%contract["address"])
                        logger.info("====NFT SellTix content TokenId %s"%nft["tokenId"])
                        tokenId = nft["tokenId"]
                        contractAddress = contract["address"]
                        try:
                            ticket = Ticket.objects.get(refContent__ticketContract__iexact=contractAddress,ticketId=int(tokenId)) 
                            # check si user possede ce ticket
                            logger.info("On compare user du ticket %s"%ticket.refUser," avec le user de la task %s"%user)
                            if ticket.refUser!=user:
                                logger.info("===Pas le bon user pour ticket ",tokenId)
                                oldOwner = ticket.refUser
                                ticket.refUser = user 
                                logger.info("===ticket change owner %s"%oldOwner)
                                logger.info("===par nouveau owner %s"%user)
                                ticket.lastOwner = oldOwner.walletAddress 
                                task.status=2        
                                ticket.save()
                                 
                            else:
                                logger.info("===ticket trouve pour user ",user," ticketRefser ",ticket.refUser)
                                task.status=2        
                                ticket.save()
                                 
                                
                        except Exception as e:
                            #Ticket selltix non trouvé en base !!! 
                            
                            message="Billet ticket Content %s TokenId<b>%s</b> appartient à wallet %s !"%(contractAddress,tokenId,checkedWalletAddress)
                            sendEmail("csurbier@idevotion.fr","[SellTix] Ticket trouvé sur blockchain mais absent en base",message)
                            task.status=3
                            task.save()
                            logger.info(e)
                    elif " - SellTix.live" in contract["name"]:
                        logger.info("====NFT SellTix Name %s"%contract["name"])
                        logger.info("====NFT SellTix Address %s"%contract["address"])
                        logger.info("====NFT SellTix TokenId %s"%nft["tokenId"])
                        tokenId = nft["tokenId"]
                        contractAddress = contract["address"]
                        try:
                            ticket = Ticket.objects.get(refTicketType__refEvent__ticketContract__iexact=contractAddress,ticketId=int(tokenId)) 
                            # check si user possede ce ticket
                            logger.info("On compare user du ticket %s"%ticket.refUser," avec le user de la task %s"%user)
                            if ticket.refUser!=user:
                                logger.info("===Pas le bon user pour ticket ",tokenId)
                                oldOwner = ticket.refUser
                                ticket.refUser = user 
                                logger.info("===ticket change owner %s"%oldOwner)
                                logger.info("===par nouveau owner %s"%user)
                                ticket.lastOwner = oldOwner.walletAddress 
                                task.status=2        
                                ticket.save()
                                 
                            else:
                                logger.info("===ticket trouve pour user ",user," ticketRefser ",ticket.refUser)
                                task.status=2        
                                ticket.save()
                                 
                                
                        except Exception as e:
                            #Ticket selltix non trouvé en base !!! 
                            
                            message="Billet ticket Event %s TokenId<b>%s</b> appartient à wallet %s !"%(contractAddress,tokenId,checkedWalletAddress)
                            sendEmail("csurbier@idevotion.fr","[SellTix] Ticket trouvé sur blockchain mais absent en base",message)
                            task.status=3
                            task.save()
                            logger.info(e)
                    else:
                        logger.info("====NFT non SellTix Name %s"%contract["name"])
                task.status=2
                task.save()            
          
    except Exception as e:
        logger.info(e)
        
        message="Billet ticket Event %s TokenId<b>%s</b> exception %s !"%(contractAddress,tokenId,str(e))
        sendEmail("csurbier@idevotion.fr","[SellTix] Erreur task",message)
                          
        task.status=3
        task.save()

def getTransactionAndCreateTicket(contract,transactionHash,resultTx,theUser,ticketType):
    #check transaction  and create tickets 
    try:
        logs = resultTx["logs"]
        for log in logs:
            topics = log["topics"]
            logger.info("===============")
            logger.info(topics)
            if len(topics)==4:
                logger.info("==Topics")
                dest = topics[2]
                token=topics[3]
                finalDest="0x"+Web3.to_hex(dest)[-40:]
                logger.info("Token ",token)
                logger.info("===compare %s avec %s"%(finalDest.lower(),theUser.walletAddress.lower()))
                if finalDest.lower()==theUser.walletAddress.lower():
                    logger.info("=== TROUVE TICKET A CREER")
                    logger.info("token %d"%Web3.to_int(token))
                    logger.info("envoi  a ",finalDest)
                    newTicket = Ticket()
                    newTicket.refUser = theUser
                    newTicket.ticketId = Web3.to_int(token)
                    newTicket.refTicketType = ticketType
                    newTicket.lastOwner = theUser.walletAddress
                    newTicket.transactionHash = transactionHash
                    #Info on blockchain... used contract to get tokenInfo 
                    ticketBlockchain = contract.functions.tickets(Web3.to_int(token)).call()
                    logger.info("Ticket lu")
                    logger.info(ticketBlockchain)
                    hashedTicket = ticketBlockchain[3] 
                    result = bytearray(hashedTicket)  # for testing
                    hxstr = "".join(["{:02x}".format(v) for v in result])
                    finalTicketCode="0x"+hxstr
                    pricePaid = ticketBlockchain[4]
                    #convert to human format 
                    finalPrice = Web3.from_wei(pricePaid,'ether')
                    newTicket.hashedTicket = finalTicketCode
                    newTicket.pricePaid = finalPrice
                    newTicket.status = 1
                    newTicket.save() 

        return "DONE"
    except Exception as e:
        logger.error(e)
        
        message="Le creation du billet mint du ticket transactionHash<b>%s</b> pour utilisateur %s a échoué !"%(transactionHash,theUser.email)
        message+=str(e)
        sendEmail("csurbier@idevotion.fr","[SellTix] Ticket miné mais creation backend failed",message)
        return "DONE"


def taskMintFreeTickets(task):
    import requests,json
    try:
        logger.info("===taskMintFreeTickets")
        logger.info(task)
        logger.info(task.metadata)
        metadata = json.loads(task.metadata)
        refOrganizer = metadata["refOrganizer"]
        ticketTypeId = metadata["ticketTypeId"]
        refEvent = metadata["refEvent"]
        recipients = metadata["recipients"] 
        # Il faut le TicketContract de l'évéenement
        theEvent = Event.objects.get(id=refEvent)
        if theEvent.status==0:
            #Wait event to be published
            return
        web3 = Web3(Web3.HTTPProvider(settings.CONTRACT_NODE_URL))
        DEBUG = os.getenv("DEBUG")
        CHAIN_ID = settings.CHAIN_ID
        if DEBUG:
            web3.middleware_onion.inject(geth_poa_middleware, layer=0)

        recipientsAddress = []
        # recipients est une liste d'email.
        # il faut regarder si un compte SellTix existe deja avec ce mail et si oui on recupere l'adresse du wallet
        # sinon on cree un compte selltix avec ce mail et on recupere l'adresse du wallet
        from backoffice.helpers import createuserWallet
        for email in recipients:
            #check if user exist
            user = User.objects.filter(email=email).first()  # Returns None if not found
            if user:
                if user.walletAddress:
                    recipientsAddress.append(user.walletAddress)
                else:
                    #need to create wallet !
                    walletAddress = createuserWallet(user)
                    if walletAddress:
                        recipientsAddress.append(walletAddress)
                
            else:
                #need to create user and wallet !
                aNewUser = User()
                aNewUser.email = email
                aNewUser.accountCreatedBySellTix = True
                aNewUser.save()
                #need to create wallet !
                walletAddress = createuserWallet(aNewUser)
                if walletAddress:
                    recipientsAddress.append(walletAddress)
        
        # GET SellTix wallet to mint
        ADRESS_TO_USE, PRIVATE_KEY_TO_USE = getFreeWallet()
        
        checkedFromWalletAddress = web3.to_checksum_address(ADRESS_TO_USE) 
        # Il faut le TicketContract de l'évéenement
        theEvent = Event.objects.get(id=refEvent)
        checkedTicketContractAddress = web3.to_checksum_address(theEvent.ticketContract) 
        # Create smart contract instance
        contract = web3.eth.contract(address=checkedTicketContractAddress, abi=settings.TICKET_ABI)
        # : call deploy sart contract function
        nonce = web3.eth.get_transaction_count(checkedFromWalletAddress,'latest')
        logger.info("===Wallet SellTix "+ADRESS_TO_USE)
        logger.info("===nonce latest : "+str(nonce))
        
        transaction = contract.functions.batchMintTicketAdmin(recipientsAddress,ticketTypeId).build_transaction({
                            'from': checkedFromWalletAddress,
                            'nonce': nonce,
                            'gasPrice': web3.to_wei('30', 'gwei'),
                            'gas': '0'
        })
        gas = web3.eth.estimate_gas(transaction)
        transaction.update({'gas': gas}) 
        signed_txn = web3.eth.account.sign_transaction(transaction, private_key=PRIVATE_KEY_TO_USE)
        receipt = web3.eth.send_raw_transaction(signed_txn.rawTransaction)
        logger.info("waiting deploy organizer contract")
        # blocking: Wait for the transaction to be mined, and get the transaction receipt
        resultTx = web3.eth.wait_for_transaction_receipt(receipt, timeout=300)
        logger.info('receipt with confirmed trx hash (after trx executed)',resultTx )
        status = resultTx["status"]
        transactionLogger(nonce,resultTx,'batchMintTicketAdmin',status,checkedFromWalletAddress)
        releaseWallet(ADRESS_TO_USE)
        if status == 1:           
            #TODO : prévenir les utilisateurs par email qu'un billet leur a été offert
            task.status=2
            task.save()
        else:
            
            #Ticket selltix non transféré ! 
            
            message="batchMintTicketAdmin échoué !"%(refOrganizer)
            sendEmail("csurbier@idevotion.fr","[SellTix] Task blockchain échoué",message)
            logger.info(resultTx)
            task.status=3
            task.save()
       
    except Exception as e:
        logger.info(e)
        
        message="batchMintTicketAdmin pour organisateur : <b>%s</b> Exception %s"%(refOrganizer,str(e))
        sendEmail("csurbier@idevotion.fr","[SellTix] Task blockchain échoué",message)
        task.status=3
        task.save()

def createOrganizerContract(task):
    #from alchemy import Alchemy, Network
    import requests,json
    try:
        logger.info("===createOrganizerContract")
        logger.info(task)
        logger.info(task.metadata)
        metadata = json.loads(task.metadata)
        refOrganizer = metadata["refOrganizer"]
        walletAddress = metadata["walletAddress"]
        web3 = Web3(Web3.HTTPProvider(settings.CONTRACT_NODE_URL))
        DEBUG = os.getenv("DEBUG")
        CHAIN_ID = settings.CHAIN_ID
        if DEBUG:
            web3.middleware_onion.inject(geth_poa_middleware, layer=0)
          
        
        # GEt wallet to mint
        ADRESS_TO_USE, PRIVATE_KEY_TO_USE = getFreeWallet()
        
        checkedWalletAddress = web3.to_checksum_address(walletAddress) 
        checkedFromWalletAddress = web3.to_checksum_address(ADRESS_TO_USE) 
        checkedContractAddress = web3.to_checksum_address(settings.ORGAFACTORY_ADDRESS) 
         # Create smart contract instance
        contract = web3.eth.contract(address=checkedContractAddress, abi=settings.ORGANISER_FACTORY_ABI)
        # : call deploy sart contract function
        nonce = web3.eth.get_transaction_count(checkedFromWalletAddress,'latest')
        logger.info("===Wallet SellTix "+ADRESS_TO_USE)
        logger.info("===nonce latest : "+str(nonce))
       
        transaction = contract.functions.deployOrganizerContract(checkedWalletAddress).build_transaction({
                            'from': checkedFromWalletAddress,
                            'nonce': nonce,
                            'gasPrice': web3.to_wei('30', 'gwei'),
                            'gas': '0'
        })
        gas = web3.eth.estimate_gas(transaction)
        transaction.update({'gas': gas}) 
        signed_txn = web3.eth.account.sign_transaction(transaction, private_key=PRIVATE_KEY_TO_USE)
        receipt = web3.eth.send_raw_transaction(signed_txn.rawTransaction)
        logger.info("waiting deploy organizer contract")
        # blocking: Wait for the transaction to be mined, and get the transaction receipt
        resultTx = web3.eth.wait_for_transaction_receipt(receipt, timeout=300)
        logger.info('receipt with confirmed trx hash (after trx executed)',resultTx )
        status = resultTx["status"]
        transactionLogger(nonce,resultTx,'deployOrganizerContract',status,checkedWalletAddress)
        releaseWallet(ADRESS_TO_USE)
        if status == 1:           
            # need to read address of deployed contract
            smartContractDeployed = contract.functions.contractForOrganizer(checkedWalletAddress).call()
            #associate created address to user organizerSmartContract
            logger.info("=== On a deployed pour ",refOrganizer)
            logger.info(smartContractDeployed)
            user = User.objects.get(id=refOrganizer)
            user.organizerContract = smartContractDeployed
            user.save()
            if user.webhookUrl:
                # need to send partner webhook
                from backoffice.helpers import notify_partner_webhook
                message = "Your organizer smart contract has been created and can be checked at the address:"+settings.POLYGON_EXPLORER+smartContractDeployed+"/"
                notify_partner_webhook(user,None,"Smart contract created",message)
            task.status=2
            task.save()
        else:
            
            #Ticket selltix non transféré ! 
            
            message="Creation smart contract pour organisateur : <b>%s</b> transfert échoué !"%(refOrganizer)
            sendEmail("csurbier@idevotion.fr","[SellTix] Task blockchain échoué",message)
            logger.info(resultTx)
            task.status=3
            task.save()
       
    except Exception as e:
        logger.info(e)
        
        message="Creation smart contract pour organisateur : <b>%s</b> Exception %s"%(refOrganizer,str(e))
        sendEmail("csurbier@idevotion.fr","[SellTix] Task blockchain échoué",message)
        task.status=3
        task.save()


def sendPolToUser(task):
    try:
        logger.info(task.metadata)
        metadata = json.loads(task.metadata)
        refOrganizer = metadata["refOrganiser"]
        refPayment = metadata["refPayment"]
        pricePol = POLPrice.objects.get(id=1)
        # On calcule pour 5€ combien de POL on peut avoir 
        # Il faut enlever les frais stripe sur 5€ (2%+0.25) 
        payment = Payment.objects.get(id=refPayment)
        stripe.api_key = settings.STRIPE_API_KEY
        try:
            payment_intent = stripe.PaymentIntent.retrieve(
                payment.paymentIntent,expand=['latest_charge.balance_transaction'],
            )
            if payment_intent:
                fee_details = payment_intent.latest_charge.balance_transaction.fee_details
                logger.info("PAyment intent : ")
                logger.info(payment_intent)
                logger.info("Fee details : ")
                logger.info(fee_details)
                stripeFees = (fee_details[0].amount)/100
            else:
                stripeFees = 0.35
        except Exception as e:
            logger.info(e)
            stripeFees = 0.35
       
        # envoi la facture 
        sendInvoice(payment)
        totalPaid = 5-stripeFees
        payment.feesSelltix= totalPaid
        payment.feesStripeForSellTix = stripeFees
        amountOfPol = totalPaid/pricePol.price
        # On prend 2% de POL
        selltixFees = amountOfPol*0.02
       
        totalPolToSend = amountOfPol-selltixFees
        logger.info("Price POL : "+str(pricePol.price))
        logger.info("Amount of POL : "+str(amountOfPol))
        logger.info("Selltix fees : "+str(selltixFees))
        logger.info("Total POL to send : "+str(totalPolToSend))
        # save infos in json in extraInfo field
        payment.extraInfo = json.dumps(
            {
                "pricePOL":pricePol.price,
                "amountOfPol":amountOfPol,
                "selltixFees":selltixFees,
                "feesStripeForSellTix":stripeFees,
                "totalPolToSend":totalPolToSend
             }
        )
        
        
        if totalPolToSend>0 and totalPolToSend<30:            
            from backoffice.helpers import sendMatic
            user = User.objects.get(id=refOrganizer)
            envoiDone = sendMatic(user.walletAddress,totalPolToSend)
            if envoiDone:
                payment.save()
                task.status=2
                task.save()
            else:
                payment.save()
                task.status=3
                task.save()
                sendEmail("csurbier@idevotion.fr","[SellTix] Task sendPolToUser envoi de pol échoué","Transaction non réussie")
        else:
            task.status=3
            task.save()
            message="Montant de pol a envoyer pas correct "+str(totalPolToSend)
            sendEmail("csurbier@idevotion.fr","[SellTix] Task sendPolToUser envoi de pol échoué",message)
    except Exception as e:
        logger.info(e)
        task.status=3
        task.save()
        message="sendPolToUser Exception %s"%(str(e))
        sendEmail("csurbier@idevotion.fr","[SellTix] Task sendPolToUser échoué",message)
        

def deployEventContract(task):
     #from alchemy import Alchemy, Network
    import json
    try:
        logger.info("===deployEventContract")
        logger.info(task)
        logger.info(task.metadata)
        metadata = json.loads(task.metadata)
        refOrganizer = metadata["refOrganiser"]
        refEvent = metadata["refEvent"]
        web3 = Web3(Web3.HTTPProvider(settings.CONTRACT_NODE_URL))
        DEBUG = os.getenv("DEBUG")
        CHAIN_ID = settings.CHAIN_ID
        if DEBUG:
            web3.middleware_onion.inject(geth_poa_middleware, layer=0)
          
       
        
        user = User.objects.get(id=refOrganizer)
        event = Event.objects.get(id=refEvent)

        checkedOrganiserWalletAddress = web3.to_checksum_address(user.walletAddress) 
        checkedOrganiserContractAddress = web3.to_checksum_address(user.organizerContract) 
         # Create smart contract instance
        contractOrganiser = web3.eth.contract(address=checkedOrganiserContractAddress, abi=settings.ORGANISER_ABI)
        contratsDeployed = contractOrganiser.functions.fetchEventsContract().call()
        logger.info("===Organiser contract deployed : ")
        logger.info(contratsDeployed)
        nbContratDeployed = len(contratsDeployed)
        logger.info("===Organiser nb contract deployed : %d"%nbContratDeployed)

         
        # the organiser needs MATIC in it's wallet          
        # should check wallet balance and send matic if needed
        # : call deploy sart contract function
        balance_wei = web3.eth.get_balance(checkedOrganiserWalletAddress)
        balance_matic = web3.from_wei(balance_wei, 'ether')
        logger.info(f"Organiser wallet balance: {balance_matic} MATIC")

        # You can then compare this balance to a minimum threshold
        min_balance_threshold = 1  # for example, 1 MATIC
        if balance_matic < min_balance_threshold:
            logger.info("Organiser wallet balance is below the threshold. Sending MATIC.")
            maticToSendAmount = "1"
            from backoffice.helpers import sendMatic
            envoiDone = sendMatic(user.walletAddress,maticToSendAmount)
            if envoiDone:
                user.maticSent=True
                user.save()
        
       
        # Get event json from event object
        jsonEvent =   {
                'id': str(event.id),
                'eventDate': int(event.eventDate.timestamp()),
                'duration': event.duration,
                'typeEvent': event.eventType,
                'name': event.name,
                'description': event.description,
                'canceled': False,  # Assuming status 2 means canceled
                'royalty': int(event.royalty),
                'sellTixRoyaltieValue': int(event.sellTixRoyaltieValue)
        } 
        nonce = web3.eth.get_transaction_count(checkedOrganiserWalletAddress,'latest')
        
         # decrypt get private key user... 
        logger.info("Decrypt organiser private key")
        thePinCodeToDecrypt = decrypt_private_key_AES256(user.pinCode,os.getenv("SECRET_PIN_KEY"))
        realCodePin = 9999 - int(thePinCodeToDecrypt)
        PRIVATE_KEY_ORGANISER = decrypt_private_key_AES256(user.privateKey,str(realCodePin))
        
        logger.info("===nonce latest : "+str(nonce))
        logger.info("==Json event")
        logger.info(jsonEvent)
        
        event_tuple = (
            jsonEvent['id'],
            jsonEvent['eventDate'],
            jsonEvent['duration'],
            jsonEvent['typeEvent'],
            jsonEvent['name'],
            jsonEvent['description'],
            jsonEvent['canceled'],
            jsonEvent['royalty'],
            jsonEvent['sellTixRoyaltieValue']
        )

        payees = [checkedOrganiserWalletAddress]
        shares = [100]

        transaction = contractOrganiser.functions.deployNewEventTicketContract(
            event_tuple,
            payees,
            shares
        ).build_transaction({
            'from': checkedOrganiserWalletAddress,
            'nonce': nonce,
            'gasPrice': web3.to_wei('30', 'gwei'),
            'gas': '0',
            'chainId': CHAIN_ID
        })
        logger.info(transaction)
        logger.info("===estimate gas")
        gas = web3.eth.estimate_gas(transaction)
        logger.info("===gas : ")
        logger.info(gas)
        logger.info("===update gas")
        transaction.update({'gas': gas}) 
       
        signed_txn = web3.eth.account.sign_transaction(transaction, private_key=PRIVATE_KEY_ORGANISER)
        transaction_hash = web3.eth.send_raw_transaction(signed_txn.rawTransaction)
        logger.info("waiting deployNewEventTicketContract ")
        # blocking: Wait for the transaction to be mined, and get the transaction receipt
        resultTx = web3.eth.wait_for_transaction_receipt(transaction_hash, timeout=300)
        
        logger.info('receipt with confirmed trx hash (after trx executed)',resultTx )
        status = resultTx["status"]
        transactionLogger(nonce,resultTx,'deployEventContract',status,checkedOrganiserWalletAddress)
        if status == 1:
            logger.info("===Transaction successful on recup adresse contract deployee")
            # need to read address of deployed contract
            eventSmartContractDeployed = contractOrganiser.functions.deployedEventContract(nbContratDeployed).call()
            logger.info("=== On a deployed eventSmartContractDeployed sur %s"%eventSmartContractDeployed)
            event.eventContract = eventSmartContractDeployed
            event.save()
            # Need to publish ticketsType related to the Event
            logger.info("===Build tickettyps json")
            ticketTypesBulk = []
            ticketsEvent = TicketType.objects.filter(refEvent=event,status=0)
            for ticketType in ticketsEvent:
                # build json 
                svgURL = ''
                if ticketType.refTicketTypeTemplate.svgUrl:
                    svgURL = ticketType.refTicketTypeTemplate.svgUrl
                jsonTicketTypeTemplate =   {
                    "gradient1Color":ticketType.refTicketTypeTemplate.gradient1Color,
                    "gradient2Color":ticketType.refTicketTypeTemplate.gradient2Color,
                    "eventTitleOne":ticketType.refTicketTypeTemplate.eventTitleOne,
                    "eventTitleTwo":ticketType.refTicketTypeTemplate.eventTitleTWo,
                    "eventTitleFont":ticketType.refTicketTypeTemplate.eventTitleFont,
                    "eventColor":ticketType.refTicketTypeTemplate.eventColor,
                    "ticketTypeFont":ticketType.refTicketTypeTemplate.ticketTypeFont,
                    "ticketTypeColor":ticketType.refTicketTypeTemplate.ticketTypeColor,
                    "price":ticketType.refTicketTypeTemplate.price,
                    "priceColor":ticketType.refTicketTypeTemplate.priceColor, 
                    "priceFont":ticketType.refTicketTypeTemplate.priceFont,
                    "fontUrl":ticketType.refTicketTypeTemplate.fontUrl,
                    "ticketType":ticketType.name,
                    "venue":'',
                    "svgUrl":svgURL
                }
                logger.info("==Json tickettypetemplate")
                logger.info(jsonTicketTypeTemplate)
                dateRevelead = 0  
                if ticketType.revealStartDate:
                    dateRevelead = int(ticketType.revealStartDate.timestamp()) 
                else:
                    dateRevelead = 0 
                
                dateDiscountEnd = 0  
                if ticketType.discountEndDate:
                    dateDiscountEnd = int(ticketType.discountEndDate.timestamp()) 
                else:
                    dateDiscountEnd = 0 

                urlHidden = ''
                if ticketType.hiddenuri:
                    urlHidden = ticketType.hiddenuri
                
                #il faut faire les conversions des valeurs float 
                
                fixAmount = int(ticketType.fixAmount * 10**18)  # Convert to wei
                ticketPrice = int(ticketType.ticketPrice * 10**18)  # Convert to wei
                discountPrice = int(ticketType.discountPrice * 10**18)  # Convert to wei 
                maxSellablePrice = int(ticketType.maxSellablePrice) # Convert to wei 
                
                ticketJson = {
                    "id":0, #Ne sera pas pris en compte car c'est le smart contract qui attribue le bon numero
                    "maxTickets":ticketType.maxTickets,
                    "maxTicketsPerUser":ticketType.maxTicketsPerUser,
                    "ticketPrice":ticketPrice,
                    "bookingStartDate":int(ticketType.bookingStartDate.timestamp()),
                    "bookingEndDate":int(ticketType.bookingEndDate.timestamp()),
                    "name":ticketType.name,
                    "revealed":ticketType.revealed,
                    "revealStartDate":dateRevelead,
                    "sellable":ticketType.sellable,
                    "maxSellablePrice":maxSellablePrice,
                    "royaltySellable":int(ticketType.royaltySellable),
                    "earlyBid":ticketType.earlyBid,
                    "discountEndDate":dateDiscountEnd,
                    "discountPrice":discountPrice,
                    "hiddenuri":urlHidden,
                    "templateId":ticketType.refTicketTypeTemplate.templateId,
                    "image": ticketType.refTicketTypeTemplate.image,
                    "fixAmount":fixAmount,
                    "freeDrink":ticketType.freeDrink,
                    "canStream":ticketType.canStream,
                    "priorityQueue":ticketType.priorityQueue,
                    "ticketDesignInfo":jsonTicketTypeTemplate
                }
                ticket_json_tuple = (
                    ticketJson['id'],
                    ticketJson['maxTickets'],
                    ticketJson['maxTicketsPerUser'],
                    ticketJson['ticketPrice'],
                    ticketJson['bookingStartDate'],
                    ticketJson['bookingEndDate'],
                    ticketJson['revealed'],  
                    ticketJson['revealStartDate'],  
                    ticketJson['sellable'],
                    ticketJson['maxSellablePrice'],
                    ticketJson['royaltySellable'],
                    ticketJson['earlyBid'],
                    ticketJson['discountPrice'],
                    ticketJson['discountEndDate'],
                    ticketJson['templateId'],
                    ticketJson['fixAmount'],
                    ticketJson['freeDrink'],
                    ticketJson['priorityQueue'],
                    ticketJson['canStream'],                   
                    ticketJson['name'],
                    ticketJson['hiddenuri'],
                    ticketJson['image'],
                    (
                        jsonTicketTypeTemplate["gradient1Color"],
                        jsonTicketTypeTemplate["gradient2Color"],
                        jsonTicketTypeTemplate["eventTitleOne"],
                        jsonTicketTypeTemplate["eventTitleTwo"],
                        jsonTicketTypeTemplate['eventTitleFont'],
                        jsonTicketTypeTemplate['eventColor'],
                        jsonTicketTypeTemplate['ticketTypeFont'],
                        jsonTicketTypeTemplate['ticketTypeColor'],
                        jsonTicketTypeTemplate['price'],
                        jsonTicketTypeTemplate['priceColor'],
                        jsonTicketTypeTemplate['priceFont'],
                        jsonTicketTypeTemplate['fontUrl'],
                        jsonTicketTypeTemplate['ticketType'],
                        jsonTicketTypeTemplate['venue'],
                        jsonTicketTypeTemplate['svgUrl']
                    )
                )
                ticketTypesBulk.append(ticket_json_tuple)
            logger.info("== JSon pour deployer en bulk")
            logger.info(ticketTypesBulk)
            # Il faut initialiser le contrat Evenement 
            # Create smart contract instance
            checkedEventContractAddress = web3.to_checksum_address(eventSmartContractDeployed) 
            eventSmartContract = web3.eth.contract(address=checkedEventContractAddress, abi=settings.EVENT_ABI)
            paymentAddress = contractOrganiser.functions.organizerEventPaymentSplitter(eventSmartContractDeployed).call()
            ticketAddress = eventSmartContract.functions.ticketContract().call() 
            ticketTypeAddress = eventSmartContract.functions.ticketTypeContract().call() 
            logger.info("==On sauve les infos ticketAdress,paymentAdresse et ticketType")
            logger.info(ticketAddress)
            logger.info(paymentAddress)
            logger.info(ticketTypeAddress)
            event.ticketContract = ticketAddress
            event.ticketTypeContract = ticketTypeAddress
            event.paymentContract = paymentAddress
            event.save()
            
            # deploy bulk tickets , on recupere le nouveau nonce pour le deployement du bulk
            nonce = web3.eth.get_transaction_count(checkedOrganiserWalletAddress,'latest')
            logger.info("===On tente de deployer le bulk ")
            transaction = eventSmartContract.functions.bulkCreateTicketType(ticketTypesBulk).build_transaction({
                'from': checkedOrganiserWalletAddress,
                'nonce': nonce,
                'gasPrice': web3.to_wei('30', 'gwei'),
                'gas': '0'
            })
            gas = web3.eth.estimate_gas(transaction)
            transaction.update({'gas': gas}) 
            logger.info("===sign transaction")
            signed_txn = web3.eth.account.sign_transaction(transaction, private_key=PRIVATE_KEY_ORGANISER)
            receipt = web3.eth.send_raw_transaction(signed_txn.rawTransaction)
            logger.info("waiting deploy bulk")
            # blocking: Wait for the transaction to be mined, and get the transaction receipt
            resultTx = web3.eth.wait_for_transaction_receipt(receipt, timeout=300)
            logger.info('receipt with confirmed trx hash (after trx executed)',resultTx )
            status = resultTx["status"]
            transactionLogger(nonce,resultTx,'bulkCreateTicketType',status,checkedOrganiserWalletAddress)
            if status == 1:
                logger.info("==Bulk deployé")
                event.status = 1
                event.save()
                # need to send partner webhook
                from backoffice.helpers import notify_partner_webhook
                message = "Your Event smart contract has been created and can be checked at the address:"+settings.POLYGON_EXPLORER+eventSmartContractDeployed+"/"
                notify_partner_webhook(user,None,"Smart contract created",message)
                task.status=2
                task.save()
            else:
                #Ticket selltix non transféré ! 
                
                message="Publish contract pour organisateur : <b>%s</b> deploy tickets bulks échoué !"%(refOrganizer)
                sendEmail("csurbier@idevotion.fr","[SellTix] Task blockchain échoué",message)
                logger.info(resultTx)
                task.status=3
                task.save()
        else:
            #Ticket selltix non transféré ! 
            
            message="Publish contract pour organisateur : <b>%s</b> deploy échoué !"%(refOrganizer)
            sendEmail("csurbier@idevotion.fr","[SellTix] Task blockchain échoué",message)
            logger.info(resultTx)
            task.status=3
            task.save()
       
    except Exception as e:
        
        message="Creation smart contract pour organisateur : <b>%s</b> Exception %s"%(refOrganizer,str(e))
        sendEmail("csurbier@idevotion.fr","[SellTix] Task blockchain échoué",message)
        task.status=3
        task.save()


@app.task(bind=True, ignore_result=True)
def sendRappelEvent(self,args):
     # send code to user using sendgrid 
     #find events in 30 minutes 
    logger.info("==== sendRappelEvent ====")
    events = Event.objects.filter(status=1,mailRappelSent=False,ended=False)
    logger.info("=== Nb Event à checker "+str(len(events)))
    for event in events: 
        try:
            logger.info("===Check event %s"%(event.name))
            if hasEventEnded(event):
                event.ended=True
                event.save()
                continue
            #Check if event is in 60 minutes
            paris_tz = pytz.timezone('Europe/Paris')
            dateToParisTimezone = getEventDateToParisTimeZone(event)
            oneHourBefore = dateToParisTimezone-timedelta(minutes=30)
            
            current_time = timezone.now().astimezone(paris_tz)
            logger.info("=== Check Rappel Event 30 min avant à envoyer - Heure Paris "+str(oneHourBefore)+" avec "+str(current_time))
            if current_time >= oneHourBefore:
                eventName=event.name 
                #Il faut recuperer tous les emails de ceux qui ont des tickets...
                emailTickets = Ticket.objects.filter(refTicketType__refEvent=event,status=1).values_list('refUser__email',flat=True)
                recipients = [{"email": email} for email in unique(emailTickets, key=lambda x: x) if email is not None]
                if recipients:
                    sg = sendgrid.SendGridAPIClient(settings.SENDGRID_API_KEY)
                    data = {
                                "personalizations": [
                                    {
                                    "to": [{"email": "contact@selltix.live"}],  
                                        "bcc": recipients,
                                        "subject": "Votre événement SellTix",
                                        "dynamic_template_data": {
                                            "eventname":eventName
                                        }
                                    }
                                ],
                                "from": {
                                    "email": "SellTix <contact@selltix.fr>"
                                },
                            
                                "template_id": settings.TEMPLATE_ID_RAPPELEVENT
                            }
                    response = sg.client.mail.send.post(request_body=data)
                    if response.status_code == 202:
                        event.mailRappelSent=True
                        event.save()
                    else:
                        logger.info("=== Rappel événement envoi %s a échoué !"%(eventName))
                        logger.info(data)
                        message="Le rappel événement envoi %s a échoué !"%(eventName)
                        sendEmail("csurbier@idevotion.fr","[SellTix] Rappel événement envoi mail échoué",message)
                        event.mailRappelSent=True
                        event.save()
        except Exception as e:
            logger.info("===Cause erreur")
            logger.error(e)
            message="Le rappel événement envoi %s a échoué !"%(eventName)
            sendEmail("csurbier@idevotion.fr","[SellTix] Rappel événement Exception",message)


@app.task(bind=True, ignore_result=True)
def checkPolPrice(self,args):
    logger.info("=== TASKS CHECK POL PRICE ===")
    try:
        from coinapi_rest_v1.restapi import CoinAPIv1
        api = CoinAPIv1(settings.COINAPI_KEY)
        exchange_rate = api.exchange_rates_get_specific_rate('POL', 'EUR')
        logger.info('Time: %s' % exchange_rate['time'])
        logger.info('Base: %s' % exchange_rate['asset_id_base'])
        logger.info('Quote: %s' % exchange_rate['asset_id_quote'])
        logger.info('Rate: %s' % exchange_rate['rate'])
        polprice = POLPrice.objects.get(id=1)
        polprice.price = exchange_rate['rate']
        polprice.save()
    except Exception as e:
        logger.error(e)
        message="Impossible de récuperer le prix du POL !"+str(e)
        sendEmail("csurbier@idevotion.fr","[SellTix] Checke POL price Exception",message)

@app.task(bind=True, ignore_result=True)
def checkContractOrganizer(self,args):
    logger.info("=== TASKS CHECK CONTRACT ORGANIZER ===")
    users  = User.objects.filter(isOrganizer=True,organizerContract=None,walletAddress__isnull=False)
    for user in users:
        # if organisateur tache pour créer son contrat
        if hasattr(user, 'seller') and user.seller.stripe_charges_enabled:
            from backoffice.models import Tasks
            import json
            logger.info("===On doit créer un contrat organisateur")
            # Batch create organizer contract
            task = Tasks()
            task.status = 0 
            task.action = "createOrganizerContract"
            task.metadata =  json.dumps({
                            "refOrganizer": str(user.id),
                            "walletAddress": user.walletAddress
            })
            task.save()
@app.task(bind=True, ignore_result=True)
def checkTasks(self,args):
    logger.info("===CHECK TASKS ")
    try:
        import requests
        urlMonitor = "https://hc-ping.com/dfd8d7d7-a464-4a7b-960b-a4a3242ea763"
        response = requests.get(urlMonitor)
        from django.db import transaction
        with transaction.atomic():
            taskToDo = Tasks.objects.filter(status=0).select_for_update().order_by("createdAt")[:10]

            logger.info("===TASKS TO DO ?"+str(len(taskToDo)))
            for task in taskToDo:
                task.status=1
                task.save()
                if task.action=="checkTickets":
                    taskCheckTickets(task)
                elif task.action=="offrirTickets":
                    taskOffrirTickets(task)
                elif task.action=="createOrganizerContract":
                    createOrganizerContract(task)
                elif task.action=="deployEventContract":
                    logger.info("===deployEventContract")
                    deployEventContract(task)
                elif task.action=="sendPolToUser":
                    logger.info("===sendPolToUser")
                    sendPolToUser(task)
                elif task.action=="mintFreeTickets":
                    taskMintFreeTickets(task)
                else:
                    logger.info("===ACTION NON DEFINIE")
                
    except Exception as e:
        logger.error(e) 


@app.task(bind=True, ignore_result=True)
def mintTicket(self,walletToUse):
        logger.info("=== MINT 2 TICKETS MAX per 10 seconds pour wallet %s"%walletToUse)
        from django.db import transaction
        ticketsToMint = TicketToMint.objects.filter(status=0,nbFailure__lte=3,withWallet=walletToUse).order_by("createdAt")[:2].select_related("refUser").select_related("refTicketType").select_related("refPayment")
        if ticketsToMint.exists():
            with transaction.atomic():
                logger.info("===On a ticketsTomint")
                logger.info(ticketsToMint)
                ids = []
                for ticket in ticketsToMint:
                    ids.append(str(ticket.id))
                 
                if len(ids) > 0:
                    #Limit 2 tickets
                    try:
                        TicketToMint.objects.select_for_update().filter(pk__in=ids).update(status=3)
                    except Exception as e:
                        logger.info(e)
                
                if walletToUse=="wallet1":
                    ADRESS_TO_USE = settings.SELLTIX_WALLET
                    PRIVATE_KEY_TO_USE = settings.SELLTIX_WALLET_PRIVATE_KEY
                elif walletToUse=="wallet2":
                    ADRESS_TO_USE = settings.SELLTIX_WALLET2
                    PRIVATE_KEY_TO_USE = settings.SELLTIX_WALLET_PRIVATE_KEY2
                elif walletToUse=="wallet3":
                    ADRESS_TO_USE = settings.SELLTIX_WALLET3
                    PRIVATE_KEY_TO_USE = settings.SELLTIX_WALLET_PRIVATE_KEY3
                elif walletToUse=="wallet4":
                    ADRESS_TO_USE = settings.SELLTIX_WALLET4
                    PRIVATE_KEY_TO_USE = settings.SELLTIX_WALLET_PRIVATE_KEY4
                elif walletToUse=="wallet5":
                    ADRESS_TO_USE = settings.SELLTIX_WALLET5
                    PRIVATE_KEY_TO_USE = settings.SELLTIX_WALLET_PRIVATE_KEY5

                #Need to wait for wallet being unlocked and then locked it while processing 
                getWalletToUseOrWait(walletToUse)
                         
                for ticketMinted in ticketsToMint:
                    try:
                        logger.info("Ok wallet %s libre, on tente de mint "%walletToUse)
                        logger.info(ticketMinted)
                        
                        if ticketMinted.nbFailure>=3:
                            logger.info("On a 3 failures, previens SellTix")
                            # warn SELLTIX
                            ticketMinted.status=2
                            ticketMinted.save()
                            message="Le mint du ticket <b>%s</b> a échoué !"%ticketMinted.id
                            sendEmail("csurbier@idevotion.fr","[SellTix] TicketToMint failed",message)
                            return
                        theUser = User.objects.get(id=ticketMinted.refUser.id)
                        web3 = Web3(Web3.HTTPProvider(settings.CONTRACT_NODE_URL))
                        DEBUG = os.getenv("DEBUG")
                        if DEBUG:
                            web3.middleware_onion.inject(geth_poa_middleware, layer=0)
                        
                        # Initialize the address calling the fOunctions/signing transactions
                        # Initialize contract ABI and address
                        # Utiliser le wallet utilisé pour la reservation
                        checkedWalletAddress = web3.to_checksum_address(ADRESS_TO_USE) 
                        # Create smart contract instance
                        checkedTicketAddress = web3.to_checksum_address(ticketMinted.refTicketType.refEvent.ticketContract)
                        contract = web3.eth.contract(address=checkedTicketAddress, abi=TICKET_ABI)
                        # : call 
                        nonce = web3.eth.get_transaction_count(checkedWalletAddress,"latest")
                        logger.info("Mint avec infos : ")
                        logger.info("nonce %s"%nonce)
                        logger.info("reservationId %s"%ticketMinted.reservationId)
                        logger.info("wallet user %s"%theUser.walletAddress)
                        logger.info("== Ticket contract %s"%checkedTicketAddress)
                        logger.info("===Avec le wallet %s"%checkedWalletAddress)
                        transaction = contract.functions.mintTicket(ticketMinted.reservationId,web3.to_checksum_address(theUser.walletAddress)).build_transaction({
                            'from': checkedWalletAddress,
                            'nonce': nonce,
                            'gasPrice': web3.to_wei('30', 'gwei'),
                            'gas': '0'
                        })

                        gas = web3.eth.estimate_gas(transaction)
                        transaction.update({'gas': gas})
                        # peut y'avoir plusieurs tickets ...
                         
                        logger.info("signe and send")
                        signed_txn = web3.eth.account.sign_transaction(transaction, private_key=PRIVATE_KEY_TO_USE)
                        receipt = web3.eth.send_raw_transaction(signed_txn.rawTransaction)
                        logger.info("waiting")
                        # blocking: Wait for the transaction to be mined, and get the transaction receipt
                        # blocking: Wait for the transaction to be mined, and get the transaction receipt
                        resultTx = web3.eth.wait_for_transaction_receipt(receipt, timeout=300)
                        logger.info('receipt with confirmed trx hash (after trx executed)')
                        logger.info(resultTx)
                        
                        status = resultTx["status"]
                        transactionLogger(nonce,resultTx,'mintTicket',status,theUser.walletAddress)
                        if status==1:
                            result = getTransactionAndCreateTicket(contract,web3.to_hex(receipt),resultTx,theUser,ticketMinted.refTicketType)
                            ticketMinted.status=1
                            ticketMinted.save()
                        else:
                            ticketMinted.transactionHash = web3.to_hex(receipt)
                            ticketMinted.status=0
                            ticketMinted.nbFailure+=1
                            ticketMinted.save()
                            
                    except Exception as e:
                        ticketMinted.nbFailure+=1
                        ticketMinted.status=0
                        ticketMinted.save()
                        logger.error(e)
                # warn SELLTIX
                logger.info("On a fini de mint releasing to pool wallet %s"%walletToUse)
                wallet_pool.release_wallet(walletToUse)