def processPointOfSalePayment(request):
    '''
    This view handles the callbacks from point-of-sale transactions.
    Please note that this will only work if you have set up your callback
    URL in Square to point to this view.
    '''
    print('Request data is: %s' % request.GET)

    # iOS transactions put all response information in the data key:
    data = json.loads(request.GET.get('data','{}'))
    if data:
        status = data.get('status')
        errorCode = data.get('error_code')
        errorDescription = errorCode

        try:
            stateData = data.get('state','')
            if stateData:
                metadata = json.loads(b64decode(unquote(stateData).encode()).decode())
            else:
                metadata = {}
        except (TypeError, ValueError, binascii.Error):
            logger.error('Invalid metadata passed from Square app.')
            messages.error(
                request,
                format_html(
                    '<p>{}</p><ul><li><strong>CODE:</strong> {}</li><li><strong>DESCRIPTION:</strong> {}</li></ul>',
                    str(_('ERROR: Error with Square point of sale transaction attempt.')),
                    str(_('Invalid metadata passed from Square app.')),
                )
            )
            return HttpResponseRedirect(reverse('showRegSummary'))

        # This is the normal transaction identifier, which will be stored in the
        # database as a SquarePaymentRecord
        serverTransId = data.get('transaction_id')

        # This is the only identifier passed for non-card transactions.
        clientTransId = data.get('client_transaction_id')
    else:
        # Android transactions use this GET response syntax
        errorCode = request.GET.get('com.squareup.pos.ERROR_CODE')
        errorDescription = request.GET.get('com.squareup.pos.ERROR_DESCRIPTION')
        status = 'ok' if not errorCode else 'error'

        # This is the normal transaction identifier, which will be stored in the
        # database as a SquarePaymentRecord
        serverTransId = request.GET.get('com.squareup.pos.SERVER_TRANSACTION_ID')

        # This is the only identifier passed for non-card transactions.
        clientTransId = request.GET.get('com.squareup.pos.CLIENT_TRANSACTION_ID')

        # Load the metadata, which includes the registration or invoice ids
        try:
            stateData = request.GET.get('com.squareup.pos.REQUEST_METADATA','')
            if stateData:
                metadata = json.loads(b64decode(unquote(stateData).encode()).decode())
            else:
                metadata = {}

        except (TypeError, ValueError, binascii.Error):
            logger.error('Invalid metadata passed from Square app.')
            messages.error(
                request,
                format_html(
                    '<p>{}</p><ul><li><strong>CODE:</strong> {}</li><li><strong>DESCRIPTION:</strong> {}</li></ul>',
                    str(_('ERROR: Error with Square point of sale transaction attempt.')),
                    str(_('Invalid metadata passed from Square app.')),
                )
            )
            return HttpResponseRedirect(reverse('showRegSummary'))

    # Other things that can be passed in the metadata
    sourceUrl = metadata.get('sourceUrl',reverse('showRegSummary'))
    successUrl = metadata.get('successUrl',reverse('registration'))
    submissionUserId = metadata.get('userId', getattr(getattr(request,'user',None),'id',None))
    transactionType = metadata.get('transaction_type')
    taxable = metadata.get('taxable', False)
    addSessionInfo = metadata.get('addSessionInfo',False)
    customerEmail = metadata.get('customerEmail')

    if errorCode or status != 'ok':
        # Return the user to their original page with the error message displayed.
        logger.error('Error with Square point of sale transaction attempt.  CODE: %s; DESCRIPTION: %s' % (errorCode, errorDescription))
        messages.error(
            request,
            format_html(
                '<p>{}</p><ul><li><strong>CODE:</strong> {}</li><li><strong>DESCRIPTION:</strong> {}</li></ul>',
                str(_('ERROR: Error with Square point of sale transaction attempt.')), errorCode, errorDescription
            )
        )
        return HttpResponseRedirect(sourceUrl)

    api_instance = TransactionsApi()
    api_instance.api_client.configuration.access_token = getattr(settings,'SQUARE_ACCESS_TOKEN','')
    location_id = getattr(settings,'SQUARE_LOCATION_ID','')

    if serverTransId:
        try:
            api_response = api_instance.retrieve_transaction(transaction_id=serverTransId,location_id=location_id)
        except ApiException:
            logger.error('Unable to find Square transaction by server ID.')
            messages.error(request,_('ERROR: Unable to find Square transaction by server ID.'))
            return HttpResponseRedirect(sourceUrl)
        if api_response.errors:
            logger.error('Unable to find Square transaction by server ID: %s' % api_response.errors)
            messages.error(request,str(_('ERROR: Unable to find Square transaction by server ID:')) + api_response.errors)
            return HttpResponseRedirect(sourceUrl)
        transaction = api_response.transaction
    elif clientTransId:
        # Try to find the transaction in the 50 most recent transactions
        try:
            api_response = api_instance.list_transactions(location_id=location_id)
        except ApiException:
            logger.error('Unable to find Square transaction by client ID.')
            messages.error(request,_('ERROR: Unable to find Square transaction by client ID.'))
            return HttpResponseRedirect(sourceUrl)
        if api_response.errors:
            logger.error('Unable to find Square transaction by client ID: %s' % api_response.errors)
            messages.error(request,str(_('ERROR: Unable to find Square transaction by client ID:')) + api_response.errors)
            return HttpResponseRedirect(sourceUrl)
        transactions_list = [x for x in api_response.transactions if x.client_id == clientTransId]
        if len(transactions_list) == 1:
            transaction = transactions_list[0]
        else:
            logger.error('Returned client transaction ID not found.')
            messages.error(request,_('ERROR: Returned client transaction ID not found.'))
            return HttpResponseRedirect(sourceUrl)
    else:
        logger.error('An unknown error has occurred with Square point of sale transaction attempt.')
        messages.error(request,_('ERROR: An unknown error has occurred with Square point of sale transaction attempt.'))
        return HttpResponseRedirect(sourceUrl)

    # Get total information from the transaction for handling invoice.
    this_total = sum([x.amount_money.amount / 100 for x in transaction.tenders or []]) - \
        sum([x.amount_money.amount / 100 for x in transaction.refunds or []])

    # Parse if a specific submission user is indicated
    submissionUser = None
    if submissionUserId:
        try:
            submissionUser = User.objects.get(id=int(submissionUserId))
        except (ValueError, ObjectDoesNotExist):
            logger.warning('Invalid user passed, submissionUser will not be recorded.')

    if 'registration' in metadata.keys():
        try:
            tr_id = int(metadata.get('registration'))
            tr = TemporaryRegistration.objects.get(id=tr_id)
        except (ValueError, TypeError, ObjectDoesNotExist):
            logger.error('Invalid registration ID passed: %s' % metadata.get('registration'))
            messages.error(
                request,
                str(_('ERROR: Invalid registration ID passed')) + ': %s' % metadata.get('registration')
            )
            return HttpResponseRedirect(sourceUrl)

        tr.expirationDate = timezone.now() + timedelta(minutes=getConstant('registration__sessionExpiryMinutes'))
        tr.save()
        this_invoice = Invoice.get_or_create_from_registration(tr, submissionUser=submissionUser)
        this_description = _('Registration Payment: #%s' % tr_id)

    elif 'invoice' in metadata.keys():
        try:
            this_invoice = Invoice.objects.get(id=int(metadata.get('invoice')))
            this_description = _('Invoice Payment: %s' % this_invoice.id)

        except (ValueError, TypeError, ObjectDoesNotExist):
            logger.error('Invalid invoice ID passed: %s' % metadata.get('invoice'))
            messages.error(
                request,
                str(_('ERROR: Invalid invoice ID passed')) + ': %s' % metadata.get('invoice')
            )
            return HttpResponseRedirect(sourceUrl)
    else:
        # Gift certificates automatically get a nicer invoice description
        if transactionType == 'Gift Certificate':
            this_description = _('Gift Certificate Purchase')
        else:
            this_description = transactionType
        this_invoice = Invoice.create_from_item(
            this_total,
            this_description,
            submissionUser=submissionUser,
            calculate_taxes=(taxable is not False),
            transactionType=transactionType,
        )

    paymentRecord, created = SquarePaymentRecord.objects.get_or_create(
        transactionId=transaction.id,
        locationId=transaction.location_id,
        defaults={'invoice': this_invoice,}
    )
    if created:
        # We process the payment now, and enqueue the job to retrieve the
        # transaction again once fees have been calculated by Square
        this_invoice.processPayment(
            amount=this_total,
            fees=0,
            paidOnline=True,
            methodName='Square Point of Sale',
            methodTxn=transaction.id,
            notify=customerEmail,
        )
    updateSquareFees.schedule(args=(paymentRecord,), delay=60)

    if addSessionInfo:
        paymentSession = request.session.get(INVOICE_VALIDATION_STR, {})

        paymentSession.update({
            'invoiceID': str(this_invoice.id),
            'amount': this_total,
            'successUrl': successUrl,
        })
        request.session[INVOICE_VALIDATION_STR] = paymentSession

    return HttpResponseRedirect(successUrl)
def processPointOfSalePayment ( request ) : print ( 'Request data is: %s' % request . GET ) data = json . loads ( request . GET . get ( 'data' , '{}' ) ) if data : status = data . get ( 'status' ) errorCode = data . get ( 'error_code' ) errorDescription = errorCode try : stateData = data . get ( 'state' , '' ) if stateData : metadata = json . loads ( b64decode ( unquote ( stateData ) . encode ( ) ) . decode ( ) ) else : metadata = { } except ( TypeError , ValueError , binascii . Error ) : logger . error ( 'Invalid metadata passed from Square app.' ) messages . error ( request , format_html ( '<p>{}</p><ul><li><strong>CODE:</strong> {}</li><li><strong>DESCRIPTION:</strong> {}</li></ul>' , str ( _ ( 'ERROR: Error with Square point of sale transaction attempt.' ) ) , str ( _ ( 'Invalid metadata passed from Square app.' ) ) , ) ) return HttpResponseRedirect ( reverse ( 'showRegSummary' ) ) serverTransId = data . get ( 'transaction_id' ) clientTransId = data . get ( 'client_transaction_id' ) else : errorCode = request . GET . get ( 'com.squareup.pos.ERROR_CODE' ) errorDescription = request . GET . get ( 'com.squareup.pos.ERROR_DESCRIPTION' ) status = 'ok' if not errorCode else 'error' serverTransId = request . GET . get ( 'com.squareup.pos.SERVER_TRANSACTION_ID' ) clientTransId = request . GET . get ( 'com.squareup.pos.CLIENT_TRANSACTION_ID' ) try : stateData = request . GET . get ( 'com.squareup.pos.REQUEST_METADATA' , '' ) if stateData : metadata = json . loads ( b64decode ( unquote ( stateData ) . encode ( ) ) . decode ( ) ) else : metadata = { } except ( TypeError , ValueError , binascii . Error ) : logger . error ( 'Invalid metadata passed from Square app.' ) messages . error ( request , format_html ( '<p>{}</p><ul><li><strong>CODE:</strong> {}</li><li><strong>DESCRIPTION:</strong> {}</li></ul>' , str ( _ ( 'ERROR: Error with Square point of sale transaction attempt.' ) ) , str ( _ ( 'Invalid metadata passed from Square app.' ) ) , ) ) return HttpResponseRedirect ( reverse ( 'showRegSummary' ) ) sourceUrl = metadata . get ( 'sourceUrl' , reverse ( 'showRegSummary' ) ) successUrl = metadata . get ( 'successUrl' , reverse ( 'registration' ) ) submissionUserId = metadata . get ( 'userId' , getattr ( getattr ( request , 'user' , None ) , 'id' , None ) ) transactionType = metadata . get ( 'transaction_type' ) taxable = metadata . get ( 'taxable' , False ) addSessionInfo = metadata . get ( 'addSessionInfo' , False ) customerEmail = metadata . get ( 'customerEmail' ) if errorCode or status != 'ok' : logger . error ( 'Error with Square point of sale transaction attempt.  CODE: %s; DESCRIPTION: %s' % ( errorCode , errorDescription ) ) messages . error ( request , format_html ( '<p>{}</p><ul><li><strong>CODE:</strong> {}</li><li><strong>DESCRIPTION:</strong> {}</li></ul>' , str ( _ ( 'ERROR: Error with Square point of sale transaction attempt.' ) ) , errorCode , errorDescription ) ) return HttpResponseRedirect ( sourceUrl ) api_instance = TransactionsApi ( ) api_instance . api_client . configuration . access_token = getattr ( settings , 'SQUARE_ACCESS_TOKEN' , '' ) location_id = getattr ( settings , 'SQUARE_LOCATION_ID' , '' ) if serverTransId : try : api_response = api_instance . retrieve_transaction ( transaction_id = serverTransId , location_id = location_id ) except ApiException : logger . error ( 'Unable to find Square transaction by server ID.' ) messages . error ( request , _ ( 'ERROR: Unable to find Square transaction by server ID.' ) ) return HttpResponseRedirect ( sourceUrl ) if api_response . errors : logger . error ( 'Unable to find Square transaction by server ID: %s' % api_response . errors ) messages . error ( request , str ( _ ( 'ERROR: Unable to find Square transaction by server ID:' ) ) + api_response . errors ) return HttpResponseRedirect ( sourceUrl ) transaction = api_response . transaction elif clientTransId : try : api_response = api_instance . list_transactions ( location_id = location_id ) except ApiException : logger . error ( 'Unable to find Square transaction by client ID.' ) messages . error ( request , _ ( 'ERROR: Unable to find Square transaction by client ID.' ) ) return HttpResponseRedirect ( sourceUrl ) if api_response . errors : logger . error ( 'Unable to find Square transaction by client ID: %s' % api_response . errors ) messages . error ( request , str ( _ ( 'ERROR: Unable to find Square transaction by client ID:' ) ) + api_response . errors ) return HttpResponseRedirect ( sourceUrl ) transactions_list = [ x for x in api_response . transactions if x . client_id == clientTransId ] if len ( transactions_list ) == 1 : transaction = transactions_list [ 0 ] else : logger . error ( 'Returned client transaction ID not found.' ) messages . error ( request , _ ( 'ERROR: Returned client transaction ID not found.' ) ) return HttpResponseRedirect ( sourceUrl ) else : logger . error ( 'An unknown error has occurred with Square point of sale transaction attempt.' ) messages . error ( request , _ ( 'ERROR: An unknown error has occurred with Square point of sale transaction attempt.' ) ) return HttpResponseRedirect ( sourceUrl ) this_total = sum ( [ x . amount_money . amount / 100 for x in transaction . tenders or [ ] ] ) - sum ( [ x . amount_money . amount / 100 for x in transaction . refunds or [ ] ] ) submissionUser = None if submissionUserId : try : submissionUser = User . objects . get ( id = int ( submissionUserId ) ) except ( ValueError , ObjectDoesNotExist ) : logger . warning ( 'Invalid user passed, submissionUser will not be recorded.' ) if 'registration' in metadata . keys ( ) : try : tr_id = int ( metadata . get ( 'registration' ) ) tr = TemporaryRegistration . objects . get ( id = tr_id ) except ( ValueError , TypeError , ObjectDoesNotExist ) : logger . error ( 'Invalid registration ID passed: %s' % metadata . get ( 'registration' ) ) messages . error ( request , str ( _ ( 'ERROR: Invalid registration ID passed' ) ) + ': %s' % metadata . get ( 'registration' ) ) return HttpResponseRedirect ( sourceUrl ) tr . expirationDate = timezone . now ( ) + timedelta ( minutes = getConstant ( 'registration__sessionExpiryMinutes' ) ) tr . save ( ) this_invoice = Invoice . get_or_create_from_registration ( tr , submissionUser = submissionUser ) this_description = _ ( 'Registration Payment: #%s' % tr_id ) elif 'invoice' in metadata . keys ( ) : try : this_invoice = Invoice . objects . get ( id = int ( metadata . get ( 'invoice' ) ) ) this_description = _ ( 'Invoice Payment: %s' % this_invoice . id ) except ( ValueError , TypeError , ObjectDoesNotExist ) : logger . error ( 'Invalid invoice ID passed: %s' % metadata . get ( 'invoice' ) ) messages . error ( request , str ( _ ( 'ERROR: Invalid invoice ID passed' ) ) + ': %s' % metadata . get ( 'invoice' ) ) return HttpResponseRedirect ( sourceUrl ) else : if transactionType == 'Gift Certificate' : this_description = _ ( 'Gift Certificate Purchase' ) else : this_description = transactionType this_invoice = Invoice . create_from_item ( this_total , this_description , submissionUser = submissionUser , calculate_taxes = ( taxable is not False ) , transactionType = transactionType , ) paymentRecord , created = SquarePaymentRecord . objects . get_or_create ( transactionId = transaction . id , locationId = transaction . location_id , defaults = { 'invoice' : this_invoice , } ) if created : this_invoice . processPayment ( amount = this_total , fees = 0 , paidOnline = True , methodName = 'Square Point of Sale' , methodTxn = transaction . id , notify = customerEmail , ) updateSquareFees . schedule ( args = ( paymentRecord , ) , delay = 60 ) if addSessionInfo : paymentSession = request . session . get ( INVOICE_VALIDATION_STR , { } ) paymentSession . update ( { 'invoiceID' : str ( this_invoice . id ) , 'amount' : this_total , 'successUrl' : successUrl , } ) request . session [ INVOICE_VALIDATION_STR ] = paymentSession return HttpResponseRedirect ( successUrl )
This view handles the callbacks from point-of-sale transactions.
    Please note that this will only work if you have set up your callback
    URL in Square to point to this view.