public override void doVerifySignature(Payment payment, bool verified)
        {
            if (verified)
            {
                BackgroundWorker bw = new BackgroundWorker();
                // what to do in the background thread
                bw.DoWork += new DoWorkEventHandler(
                    delegate(object o, DoWorkEventArgs args)
                {
                    notifyObserversUiState(new UiStateMessage(UiState.RECEIPT_OPTIONS, "Customer is selecting receipt type.", UiDirection.ENTER, new InputOption[0]));
                    Console.WriteLine("Received UiStateMessage: RECEIPT_OPTIONS Customer is selecting receipt type. Enter");
                    Thread.Sleep(3000);
                    notifyObserversUiState(new UiStateMessage(UiState.RECEIPT_OPTIONS, "Customer is selecting receipt type.", UiDirection.EXIT, new InputOption[0]));
                    Console.WriteLine("Received UiStateMessage: RECEIPT_OPTIONS Customer is selecting receipt type. Exit");

                    FinishOkMessage msg  = new FinishOkMessage();
                    msg.payment          = payment;
                    msg.payment.order    = new Reference();
                    msg.payment.order.id = "abc123";
                    notifyObserversFinishOk(msg);
                    Console.WriteLine("Received FINISH_OK: " + msg.payment);
                });
                bw.RunWorkerAsync();
            }
            else
            {
                notifyObserversFinishCancel();
                Console.WriteLine("Received FinishCancelMessage: FINISH_CANCEL");
            }
        }
        public override void doRefundPayment(string orderId, string paymentId, long?amount, bool?fullRefund)
        {
            notifyObserversUiState(new UiStateMessage(UiState.RECEIPT_OPTIONS, "Customer is selecting receipt type.", UiDirection.ENTER, new InputOption[0]));
            Console.WriteLine("Received UiStateMessage: RECEIPT_OPTIONS Customer is selecting receipt type. Enter");
            Thread.Sleep(3000);
            notifyObserversUiState(new UiStateMessage(UiState.RECEIPT_OPTIONS, "Customer is selecting receipt type.", UiDirection.EXIT, new InputOption[0]));
            Console.WriteLine("Received UiStateMessage: RECEIPT_OPTIONS Customer is selecting receipt type. Exit");
            Thread.Sleep(3000);

            Refund refund = new Refund();

            refund.payment = new Reference();
            if (paymentId != null)
            {
                refund.payment.id = paymentId;
            }
            refund.orderRef = new Reference();
            if (orderId != null)
            {
                refund.orderRef.id = orderId;
            }
            Object tempPayment;

            TempObjectMap.TryGetValue(paymentId, out tempPayment);
            if (tempPayment != null)
            {
                if (((Payment)tempPayment).tipAmount > 0)
                {
                    refund.amount = ((Payment)tempPayment).amount + ((Payment)tempPayment).tipAmount;
                }
                else
                {
                    refund.amount = ((Payment)tempPayment).amount;
                }
            }
            refund.id = Guid.NewGuid().ToString();
            FinishOkMessage okMsg = new FinishOkMessage();

            okMsg.refund = refund;
            notifyObserversFinishOk(okMsg);
            Console.WriteLine("Received FINISH_OK: " + okMsg.refund);
        }
示例#3
0
 public void notifyObserversFinishOk(FinishOkMessage msg)
 {
     NotifyObservers(observer =>
     {
         if (msg.payment != null)
         {
             observer.onFinishOk(msg.payment, msg.signature, msg.requestInfo);
         }
         else if (msg.credit != null)
         {
             observer.onFinishOk(msg.credit);
         }
         else if (msg.refund != null)
         {
             observer.onFinishOk(msg.refund);
         }
         else
         {
             // Console.WriteLine("Don't know what to do with this Finish OK message: " + JsonUtils.Serialize(msg));
         }
     });
 }
 public void notifyObserversFinishOk(FinishOkMessage msg)
 {
     foreach (ICloverDeviceObserver observer in deviceObservers)
     {
         if (msg.payment != null)
         {
             observer.onFinishOk(msg.payment, msg.signature, msg.requestInfo);
         }
         else if (msg.credit != null)
         {
             observer.onFinishOk(msg.credit);
         }
         else if (msg.refund != null)
         {
             observer.onFinishOk(msg.refund);
         }
         else
         {
             Console.WriteLine("Don't know what to do with this Finish OK message: " + JsonUtils.serialize(msg));
         }
     }
 }
        public void notifyObserversFinishOk(FinishOkMessage msg)
        {
            BackgroundWorker bw = new BackgroundWorker();

            // what to do in the background thread
            bw.DoWork += new DoWorkEventHandler(
                delegate(object o, DoWorkEventArgs args)
            {
                foreach (ICloverDeviceObserver observer in deviceObservers)
                {
                    if (msg.payment != null)
                    {
                        observer.onFinishOk(msg.payment, msg.signature);
                    }
                    else if (msg.credit != null)
                    {
                        observer.onFinishOk(msg.credit);
                    }
                }
            });
            bw.RunWorkerAsync();
        }
 public void notifyObserversFinishOk(FinishOkMessage msg)
 {
     BackgroundWorker bw = new BackgroundWorker();
     // what to do in the background thread
     bw.DoWork += new DoWorkEventHandler(
     delegate (object o, DoWorkEventArgs args)
     {
         foreach (ICloverDeviceObserver observer in deviceObservers)
         {
             if (msg.payment != null)
             {
                 observer.onFinishOk(msg.payment, msg.signature);
             }
             else if (msg.credit != null)
             {
                 observer.onFinishOk(msg.credit);
             }
         }
     });
     bw.RunWorkerAsync();
 }
        public override void doVerifySignature(Payment payment, bool verified)
        {
            if(verified)
            {
                BackgroundWorker bw = new BackgroundWorker();
                // what to do in the background thread
                bw.DoWork += new DoWorkEventHandler(
                delegate (object o, DoWorkEventArgs args)
                {
                    notifyObserversUiState(new UiStateMessage(UiState.RECEIPT_OPTIONS, "Customer is selecting receipt type.", UiDirection.ENTER, new InputOption[0]));
                    Console.WriteLine("Received UiStateMessage: RECEIPT_OPTIONS Customer is selecting receipt type. Enter");
                    Thread.Sleep(3000);
                    notifyObserversUiState(new UiStateMessage(UiState.RECEIPT_OPTIONS, "Customer is selecting receipt type.", UiDirection.EXIT, new InputOption[0]));
                    Console.WriteLine("Received UiStateMessage: RECEIPT_OPTIONS Customer is selecting receipt type. Exit");

                    FinishOkMessage msg = new FinishOkMessage();
                    msg.payment = payment;
                    msg.payment.order = new Reference();
                    msg.payment.order.id = "abc123";
                    notifyObserversFinishOk(msg);
                    Console.WriteLine("Received FINISH_OK: " + msg.payment);
                });
                bw.RunWorkerAsync();
            }
            else
            {
                notifyObserversFinishCancel();
                Console.WriteLine("Received FinishCancelMessage: FINISH_CANCEL");
            }
        }
        public override void doTxStart(PayIntent payIntent, Order order, bool suppressTipsOnScreen)
        {
            BackgroundWorker bw = new BackgroundWorker();
            // what to do in the background thread
            bw.DoWork += new DoWorkEventHandler(
            delegate (object o, DoWorkEventArgs args)
            {
                if (payIntent.amount > 0 && payIntent.transactionType == PayIntent.TransactionType.PAYMENT)
                {
                    if(payIntent.amount > 4000 && !suppressTipsOnScreen)
                    {
                        // let's tip
                        notifyObserversUiState(new UiStateMessage(UiState.ADD_TIP, "Customer is tipping...", UiDirection.ENTER, new InputOption[0]));
                        Console.WriteLine("Received UiStateMessage: ADD_TIP Customer is tipping... Enter");
                        Thread.Sleep(1000);
                        notifyObserversUiState(new UiStateMessage(UiState.ADD_TIP, "Customer is tipping...", UiDirection.EXIT, new InputOption[0]));
                        Console.WriteLine("Received UiStateMessage: ADD_TIP Customer is tipping... Exit");
                        payIntent.tipAmount = (long)(payIntent.amount * 0.1f);
                    }
                    notifyObserversUiState(new UiStateMessage(UiState.START, "Customer is choosing payment method.", UiDirection.ENTER, new InputOption[0]));
                    Console.WriteLine("Received UiStateMessage: START Customer is choosing payment method. Enter");
                    Thread.Sleep(1000);
                    notifyObserversUiState(new UiStateMessage(UiState.START, "Customer is choosing payment method.", UiDirection.EXIT, new InputOption[0]));
                    Console.WriteLine("Received UiStateMessage: START Customer is choosing payment method. Exit");
                    notifyObserversUiState(new UiStateMessage(UiState.PROCESSING, "Processing...", UiDirection.ENTER, new InputOption[0]));
                    Console.WriteLine("Received UiStateMessage: PROCESSING Processing... Enter");
                    Thread.Sleep(1000);
                    notifyObserversUiState(new UiStateMessage(UiState.PROCESSING, "Processing...", UiDirection.EXIT, new InputOption[0]));
                    Console.WriteLine("Received UiStateMessage: PROCESSING Processing... Exit");

                    if (payIntent.amount < 5000) // less than 50
                    {
                        Payment payment = new Payment();
                        payment.amount =  payIntent.amount;
                        payment.id = Guid.NewGuid().ToString();
                        payment.employee = new Reference();
                        payment.employee.id = Guid.NewGuid().ToString();
                        payment.order = new Reference();
                        if (order != null)
                        {
                            payment.order.id = order.id;
                        }
                        FinishOkMessage okMsg = new FinishOkMessage();
                        payment.cardTransaction = new CardTransaction();
                        payment.cardTransaction.last4 = "0123";
                        payment.cardTransaction.token = "1234567890123456";
                        TempObjectMap.Add(payment.id, payment);
                        okMsg.payment = payment;
                        notifyObserversFinishOk(okMsg);
                        Console.WriteLine("Received FINISH_OK: " + okMsg.payment);
                    }
                    else if(payIntent.amount > 10000 && payIntent.amount < 15000)
                    {
                        // if payment without tip is $100-$150 then simulate cancel transaction
                        notifyObserversFinishCancel();
                        Console.WriteLine("Received FinishCancel Message: ");
                    }
                    else
                    {

                        notifyObserversUiState(new UiStateMessage(UiState.ADD_SIGNATURE, "Waiting for signature...", UiDirection.ENTER, new InputOption[0]));
                        Console.WriteLine("Received UiStateMessage: ADD_SIGNATURE Waiting for Signature... Enter");
                        Thread.Sleep(3000);
                        notifyObserversUiState(new UiStateMessage(UiState.ADD_SIGNATURE, "Waiting for signature...", UiDirection.EXIT, new InputOption[0]));
                        Console.WriteLine("Received UiStateMessage: ADD_SIGNATURE Waiting for Signature... Exit");

                        Signature2 sig = JsonUtils.deserialize<Signature2>("{\"strokes\":[{\"points\":[{\"x\":174,\"y\":341},{\"x\":177,\"y\":338},{\"x\":183,\"y\":330},{\"x\":189,\"y\":323},{\"x\":200,\"y\":313},{\"x\":208,\"y\":305},{\"x\":217,\"y\":296},{\"x\":230,\"y\":284},{\"x\":241,\"y\":271},{\"x\":252,\"y\":257},{\"x\":261,\"y\":243},{\"x\":267,\"y\":233},{\"x\":273,\"y\":220},{\"x\":277,\"y\":206},{\"x\":279,\"y\":196},{\"x\":278,\"y\":182},{\"x\":275,\"y\":173},{\"x\":272,\"y\":164},{\"x\":267,\"y\":156},{\"x\":262,\"y\":151},{\"x\":252,\"y\":144},{\"x\":244,\"y\":141},{\"x\":235,\"y\":141},{\"x\":226,\"y\":144},{\"x\":217,\"y\":148},{\"x\":209,\"y\":154},{\"x\":202,\"y\":162},{\"x\":197,\"y\":171},{\"x\":195,\"y\":183},{\"x\":193,\"y\":195},{\"x\":195,\"y\":209},{\"x\":202,\"y\":222},{\"x\":208,\"y\":231},{\"x\":219,\"y\":241},{\"x\":231,\"y\":248},{\"x\":242,\"y\":253},{\"x\":253,\"y\":255},{\"x\":271,\"y\":256},{\"x\":285,\"y\":254},{\"x\":302,\"y\":252},{\"x\":311,\"y\":249},{\"x\":320,\"y\":245},{\"x\":329,\"y\":241},{\"x\":337,\"y\":236},{\"x\":344,\"y\":233},{\"x\":349,\"y\":231},{\"x\":352,\"y\":229},{\"x\":351,\"y\":234},{\"x\":350,\"y\":240},{\"x\":347,\"y\":247},{\"x\":343,\"y\":255},{\"x\":336,\"y\":267},{\"x\":327,\"y\":277},{\"x\":316,\"y\":287},{\"x\":302,\"y\":296},{\"x\":283,\"y\":301},{\"x\":264,\"y\":304},{\"x\":244,\"y\":305},{\"x\":227,\"y\":301},{\"x\":213,\"y\":298},{\"x\":204,\"y\":292},{\"x\":195,\"y\":287},{\"x\":190,\"y\":283},{\"x\":187,\"y\":280},{\"x\":193,\"y\":284},{\"x\":200,\"y\":288},{\"x\":214,\"y\":294},{\"x\":232,\"y\":303},{\"x\":251,\"y\":312},{\"x\":272,\"y\":320},{\"x\":292,\"y\":328},{\"x\":313,\"y\":332},{\"x\":333,\"y\":334},{\"x\":351,\"y\":332},{\"x\":368,\"y\":326},{\"x\":378,\"y\":317},{\"x\":390,\"y\":307},{\"x\":400,\"y\":300},{\"x\":407,\"y\":292},{\"x\":412,\"y\":284},{\"x\":415,\"y\":275},{\"x\":416,\"y\":268},{\"x\":415,\"y\":261},{\"x\":410,\"y\":259},{\"x\":401,\"y\":261},{\"x\":393,\"y\":266},{\"x\":381,\"y\":275},{\"x\":376,\"y\":282},{\"x\":372,\"y\":295},{\"x\":371,\"y\":304},{\"x\":375,\"y\":312},{\"x\":372,\"y\":318},{\"x\":387,\"y\":326},{\"x\":396,\"y\":329},{\"x\":404,\"y\":330},{\"x\":412,\"y\":328},{\"x\":419,\"y\":322},{\"x\":424,\"y\":314},{\"x\":426,\"y\":305},{\"x\":424,\"y\":294},{\"x\":419,\"y\":284},{\"x\":415,\"y\":278},{\"x\":405,\"y\":270},{\"x\":398,\"y\":267},{\"x\":393,\"y\":265},{\"x\":391,\"y\":266},{\"x\":394,\"y\":273},{\"x\":399,\"y\":278},{\"x\":410,\"y\":286},{\"x\":426,\"y\":292},{\"x\":444,\"y\":295},{\"x\":463,\"y\":294},{\"x\":477,\"y\":292},{\"x\":486,\"y\":287},{\"x\":495,\"y\":282},{\"x\":501,\"y\":276},{\"x\":507,\"y\":270},{\"x\":511,\"y\":265},{\"x\":513,\"y\":260},{\"x\":508,\"y\":260},{\"x\":502,\"y\":263},{\"x\":495,\"y\":268},{\"x\":489,\"y\":276},{\"x\":485,\"y\":285},{\"x\":482,\"y\":293},{\"x\":485,\"y\":300},{\"x\":489,\"y\":304},{\"x\":494,\"y\":308},{\"x\":501,\"y\":308},{\"x\":507,\"y\":304},{\"x\":512,\"y\":300},{\"x\":517,\"y\":294},{\"x\":518,\"y\":289},{\"x\":520,\"y\":283},{\"x\":523,\"y\":279},{\"x\":523,\"y\":276},{\"x\":525,\"y\":274},{\"x\":530,\"y\":272},{\"x\":538,\"y\":270},{\"x\":548,\"y\":268},{\"x\":563,\"y\":267},{\"x\":580,\"y\":267},{\"x\":590,\"y\":266},{\"x\":600,\"y\":265},{\"x\":609,\"y\":264},{\"x\":616,\"y\":263},{\"x\":622,\"y\":262},{\"x\":626,\"y\":261},{\"x\":622,\"y\":262},{\"x\":613,\"y\":264},{\"x\":597,\"y\":270},{\"x\":582,\"y\":279},{\"x\":568,\"y\":290},{\"x\":561,\"y\":299},{\"x\":557,\"y\":306},{\"x\":559,\"y\":315},{\"x\":565,\"y\":321},{\"x\":572,\"y\":326},{\"x\":583,\"y\":325},{\"x\":600,\"y\":316},{\"x\":614,\"y\":304},{\"x\":625,\"y\":289},{\"x\":631,\"y\":269},{\"x\":634,\"y\":247},{\"x\":633,\"y\":222},{\"x\":630,\"y\":196},{\"x\":627,\"y\":170},{\"x\":626,\"y\":150},{\"x\":624,\"y\":134},{\"x\":625,\"y\":125},{\"x\":626,\"y\":117},{\"x\":627,\"y\":111},{\"x\":628,\"y\":109},{\"x\":629,\"y\":115},{\"x\":632,\"y\":129},{\"x\":638,\"y\":152},{\"x\":645,\"y\":177},{\"x\":654,\"y\":205},{\"x\":663,\"y\":235},{\"x\":674,\"y\":264},{\"x\":684,\"y\":288},{\"x\":693,\"y\":304},{\"x\":697,\"y\":313},{\"x\":701,\"y\":314}]}],\"height\":666,\"width\":799}");

                        // send signature...
                        Payment payment = new Payment();
                        payment.amount = payIntent.amount;
                        payment.id = Guid.NewGuid().ToString();
                        payment.employee = new Reference();
                        payment.employee.id = Guid.NewGuid().ToString();
                        payment.order = new Reference();
                        if (order != null)
                        {
                            payment.order.id = order.id;
                        }

                        if(payIntent.tipAmount.HasValue)
                        {
                            payment.tipAmount = payIntent.tipAmount.Value;
                        }
                        TempObjectMap.Add(payment.id, payment);
                        VerifySignatureMessage msg = new VerifySignatureMessage();
                        msg.signature = sig;
                        msg.payment = payment;
                        notifyObserversVerifySignature(msg);
                        Console.WriteLine("Received VerifySignatureMessage: " + JsonUtils.serialize(msg));

                    }
                }
                else if (payIntent.amount < 0 && payIntent.transactionType == PayIntent.TransactionType.CREDIT)
                {
                    notifyObserversUiState(new UiStateMessage(UiState.START, "Customer is choosing payment method.", UiDirection.ENTER, new InputOption[0]));
                    Console.WriteLine("Received UiStateMessage: START Customer is choosing payment method... Enter");
                    Thread.Sleep(1000);
                    notifyObserversUiState(new UiStateMessage(UiState.START, "Customer is choosing payment method.", UiDirection.EXIT, new InputOption[0]));
                    Console.WriteLine("Received UiStateMessage: START Customer is choosing payment method... Exit");
                    notifyObserversUiState(new UiStateMessage(UiState.PROCESSING, "Processing...", UiDirection.ENTER, new InputOption[0]));
                    Console.WriteLine("Received UiStateMessage: PROCESSING Processing... Enter");
                    Thread.Sleep(3000);
                    notifyObserversUiState(new UiStateMessage(UiState.PROCESSING, "Processing...", UiDirection.EXIT, new InputOption[0]));
                    Console.WriteLine("Received UiStateMessage: PROCESSING Processing... Exit");
                    notifyObserversUiState(new UiStateMessage(UiState.RECEIPT_OPTIONS, "Customer is selecting receipt type.", UiDirection.ENTER, new InputOption[0]));
                    Console.WriteLine("Received UiStateMessage: RECEIPT_OPTIONS Customer is selecting receipt type. Enter");
                    Thread.Sleep(3000);
                    notifyObserversUiState(new UiStateMessage(UiState.RECEIPT_OPTIONS, "Customer is selecting receipt type.", UiDirection.EXIT, new InputOption[0]));
                    Console.WriteLine("Received UiStateMessage: RECEIPT_OPTIONS Customer is selecting receipt type. Exit");

                    Credit credit = new Credit();
                    credit.amount = payIntent.amount;
                    credit.id = Guid.NewGuid().ToString();
                    FinishOkMessage okMsg = new FinishOkMessage();
                    credit.cardTransaction = new CardTransaction();
                    credit.cardTransaction.last4 = "0123";
                    okMsg.credit = credit;
                    TempObjectMap.Add(credit.id, credit);
                    notifyObserversFinishOk(okMsg);
                    Console.WriteLine("Received FinishOkMessage: FINISH_OK");
                }
            });
            bw.RunWorkerAsync();
        }
        public override void doRefundPayment(string orderId, string paymentId, long? amount, bool? fullRefund)
        {
            notifyObserversUiState(new UiStateMessage(UiState.RECEIPT_OPTIONS, "Customer is selecting receipt type.", UiDirection.ENTER, new InputOption[0]));
            Console.WriteLine("Received UiStateMessage: RECEIPT_OPTIONS Customer is selecting receipt type. Enter");
            Thread.Sleep(3000);
            notifyObserversUiState(new UiStateMessage(UiState.RECEIPT_OPTIONS, "Customer is selecting receipt type.", UiDirection.EXIT, new InputOption[0]));
            Console.WriteLine("Received UiStateMessage: RECEIPT_OPTIONS Customer is selecting receipt type. Exit");
            Thread.Sleep(3000);

            Refund refund = new Refund();
            refund.payment = new Reference();
            if (paymentId != null)
            {
                refund.payment.id = paymentId;
            }
            refund.orderRef = new Reference();
            if (orderId != null)
            {
                refund.orderRef.id = orderId;
            }
            Object tempPayment;
            TempObjectMap.TryGetValue(paymentId, out tempPayment);
            if (tempPayment != null)
            {
                if (((Payment)tempPayment).tipAmount > 0)
                {
                    refund.amount = ((Payment)tempPayment).amount + ((Payment)tempPayment).tipAmount;
                }
                else
                {
                    refund.amount = ((Payment)tempPayment).amount;
                }
            }
            refund.id = Guid.NewGuid().ToString();
            FinishOkMessage okMsg = new FinishOkMessage();
            okMsg.refund = refund;
            notifyObserversFinishOk(okMsg);
            Console.WriteLine("Received FINISH_OK: " + okMsg.refund);
        }
示例#10
0
        /// <summary>
        /// Parse the generic message and figure out which handler should be used for processing
        /// </summary>
        /// <param name="message">The message.</param>
        public void onMessage(string message)
        {
#if DEBUG
            Console.WriteLine("Received raw message: " + message);
#endif
            RemoteMessage rMessage = null;
            try
            {
                // Note: This handling was changed after the 1.4.2 release to properly suppress uknown messages.
                //       Old versions of the WinSDK will crash with unknown messages, and old versions are still expected to be in customer's hands.
                //       When testing releases, make sure any suppressed errors here are paid proper backwards-compatible attention and tested

                // Deserialize the message object to a real object
                rMessage             = JsonUtils.DeserializeSdk <RemoteMessage>(message);
                remoteMessageVersion = Math.Max(remoteMessageVersion, rMessage.version);
            }
            catch (Exception exception)
            {
                // if a remote message can't be parsed, ignore this unknown message; log as appropriate
                // - and verify backwards compatiblility story since old WinSDK releases will crash

                // TODO: Log message and exception in new logging
            }

            // Handle and route known messages appropriately
            if (rMessage != null)
            {
                switch (rMessage.method)
                {
                case Methods.BREAK:
                    break;

                case Methods.ACK:
                    AcknowledgementMessage ackMessage = JsonUtils.DeserializeSdk <AcknowledgementMessage>(rMessage.payload);
                    notifyObserverAck(ackMessage);
                    break;

                case Methods.CASHBACK_SELECTED:
                    CashbackSelectedMessage cbsMessage = JsonUtils.DeserializeSdk <CashbackSelectedMessage>(rMessage.payload);
                    notifyObserversCashbackSelected(cbsMessage);
                    break;

                case Methods.DISCOVERY_RESPONSE:
                    DiscoveryResponseMessage drMessage = JsonUtils.DeserializeSdk <DiscoveryResponseMessage>(rMessage.payload);
                    deviceInfo.name   = drMessage.name;
                    deviceInfo.serial = drMessage.serial;
                    deviceInfo.model  = drMessage.model;
                    notifyObserversDiscoveryResponse(drMessage);
                    break;

                case Methods.FINISH_CANCEL:
                    FinishCancelMessage finishCancelMessage = JsonUtils.DeserializeSdk <FinishCancelMessage>(rMessage.payload);
                    notifyObserversFinishCancel(finishCancelMessage.requestInfo);
                    break;

                case Methods.FINISH_OK:
                    FinishOkMessage fokmsg = JsonUtils.DeserializeSdk <FinishOkMessage>(rMessage.payload);
                    notifyObserversFinishOk(fokmsg);
                    break;

                case Methods.KEY_PRESS:
                    KeyPressMessage kpm = JsonUtils.DeserializeSdk <KeyPressMessage>(rMessage.payload);
                    notifyObserversKeyPressed(kpm);
                    break;

                case Methods.ORDER_ACTION_RESPONSE:
                    break;

                case Methods.PARTIAL_AUTH:
                    PartialAuthMessage partialAuth = JsonUtils.DeserializeSdk <PartialAuthMessage>(rMessage.payload);
                    notifyObserversPartialAuth(partialAuth);
                    break;

                case Methods.PAYMENT_VOIDED:
                    // this seems to only gets called if a Signature is "Canceled" on the device
                    break;

                case Methods.CONFIRM_PAYMENT_MESSAGE:
                    setPaymentConfirmationIdle(false);
                    ConfirmPaymentMessage confirmPaymentMessage = JsonUtils.DeserializeSdk <ConfirmPaymentMessage>(rMessage.payload);
                    notifyObserversConfirmPayment(confirmPaymentMessage);
                    break;

                case Methods.TIP_ADDED:
                    TipAddedMessage tipMessage = JsonUtils.DeserializeSdk <TipAddedMessage>(rMessage.payload);
                    notifyObserversTipAdded(tipMessage);
                    break;

                case Methods.TX_START_RESPONSE:
                    TxStartResponseMessage txsrm = JsonUtils.DeserializeSdk <TxStartResponseMessage>(rMessage.payload);
                    notifyObserversTxStartResponse(txsrm);
                    break;

                case Methods.TX_STATE:
                    TxStateMessage txStateMsg = JsonUtils.DeserializeSdk <TxStateMessage>(rMessage.payload);
                    notifyObserversTxState(txStateMsg);
                    break;

                case Methods.UI_STATE:
                    UiStateMessage uiStateMsg = JsonUtils.DeserializeSdk <UiStateMessage>(rMessage.payload);
                    notifyObserversUiState(uiStateMsg);
                    break;

                case Methods.VERIFY_SIGNATURE:
                    paymentRejected = false;
                    VerifySignatureMessage vsigMsg = JsonUtils.DeserializeSdk <VerifySignatureMessage>(rMessage.payload);
                    notifyObserversVerifySignature(vsigMsg);
                    break;

                case Methods.REFUND_RESPONSE:
                    RefundResponseMessage refRespMsg = JsonUtils.DeserializeSdk <RefundResponseMessage>(rMessage.payload);
                    notifyObserversRefundPaymentResponse(refRespMsg);
                    break;

                case Methods.TIP_ADJUST_RESPONSE:
                    TipAdjustResponseMessage tipAdjustMsg = JsonUtils.DeserializeSdk <TipAdjustResponseMessage>(rMessage.payload);
                    notifyObserversTipAdjusted(tipAdjustMsg);
                    break;

                case Methods.REFUND_REQUEST:
                    //Outbound no-op
                    break;

                case Methods.VAULT_CARD_RESPONSE:
                    VaultCardResponseMessage vcrMsg = JsonUtils.DeserializeSdk <VaultCardResponseMessage>(rMessage.payload);
                    notifyObserversVaultCardResponse(vcrMsg);
                    break;

                case Methods.CARD_DATA_RESPONSE:
                    ReadCardDataResponseMessage rcdrMsg = JsonUtils.DeserializeSdk <ReadCardDataResponseMessage>(rMessage.payload);
                    notifyObserversReadCardDataResponse(rcdrMsg);
                    break;

                case Methods.CAPTURE_PREAUTH_RESPONSE:
                    CapturePreAuthResponseMessage carMsg = JsonUtils.DeserializeSdk <CapturePreAuthResponseMessage>(rMessage.payload);
                    notifyObserversCapturePreAuthResponse(carMsg);
                    break;

                case Methods.CLOSEOUT_RESPONSE:
                    CloseoutResponseMessage crMsg = JsonUtils.DeserializeSdk <CloseoutResponseMessage>(rMessage.payload);
                    notifyObserversCloseoutResponse(crMsg);
                    break;

                case Methods.RETRIEVE_PENDING_PAYMENTS_RESPONSE:
                    RetrievePendingPaymentsResponseMessage rpprMsg = JsonUtils.DeserializeSdk <RetrievePendingPaymentsResponseMessage>(rMessage.payload);
                    notifyObserversPendingPaymentsResponse(rpprMsg);
                    break;

                case Methods.ACTIVITY_RESPONSE:
                    ActivityResponseMessage arm = JsonUtils.DeserializeSdk <ActivityResponseMessage>(rMessage.payload);
                    notifyObserversActivityResponse(arm);
                    break;

                case Methods.ACTIVITY_MESSAGE_FROM_ACTIVITY:
                    ActivityMessageFromActivity amfa = JsonUtils.DeserializeSdk <ActivityMessageFromActivity>(rMessage.payload);
                    notifyObserversActivityMessage(amfa);
                    break;

                case Methods.RESET_DEVICE_RESPONSE:
                    ResetDeviceResponseMessage rdrm = JsonUtils.DeserializeSdk <ResetDeviceResponseMessage>(rMessage.payload);
                    notifyObserversDeviceReset(rdrm);
                    break;

                case Methods.RETRIEVE_DEVICE_STATUS_RESPONSE:
                    RetrieveDeviceStatusResponseMessage rdsrm = JsonUtils.DeserializeSdk <RetrieveDeviceStatusResponseMessage>(rMessage.payload);
                    notifyObserversRetrieveDeviceStatusResponse(rdsrm);
                    break;

                case Methods.DISCOVERY_REQUEST:
                    //Outbound no-op
                    break;

                case Methods.ORDER_ACTION_ADD_DISCOUNT:
                    //Outbound no-op
                    break;

                case Methods.ORDER_ACTION_ADD_LINE_ITEM:
                    //Outbound no-op
                    break;

                case Methods.ORDER_ACTION_REMOVE_LINE_ITEM:
                    //Outbound no-op
                    break;

                case Methods.ORDER_ACTION_REMOVE_DISCOUNT:
                    //Outbound no-op
                    break;

                case Methods.PRINT_CREDIT:
                    CreditPrintMessage cpm = JsonUtils.DeserializeSdk <CreditPrintMessage>(rMessage.payload);
                    notifyObserversPrintCredit(cpm);
                    break;

                case Methods.PRINT_CREDIT_DECLINE:
                    DeclineCreditPrintMessage dcpm = JsonUtils.DeserializeSdk <DeclineCreditPrintMessage>(rMessage.payload);
                    notifyObserversPrintCreditDecline(dcpm);
                    break;

                case Methods.PRINT_PAYMENT:
                    PaymentPrintMessage ppm = JsonUtils.DeserializeSdk <PaymentPrintMessage>(rMessage.payload);
                    notifyObserversPrintPayment(ppm);
                    break;

                case Methods.PRINT_PAYMENT_DECLINE:
                    DeclinePaymentPrintMessage dppm = JsonUtils.DeserializeSdk <DeclinePaymentPrintMessage>(rMessage.payload);
                    notifyObserversPrintPaymentDecline(dppm);
                    break;

                case Methods.PRINT_PAYMENT_MERCHANT_COPY:
                    PaymentPrintMerchantCopyMessage ppmcm = JsonUtils.DeserializeSdk <PaymentPrintMerchantCopyMessage>(rMessage.payload);
                    notifyObserversPrintMerchantCopy(ppmcm);
                    break;

                case Methods.REFUND_PRINT_PAYMENT:
                    RefundPaymentPrintMessage rppm = JsonUtils.DeserializeSdk <RefundPaymentPrintMessage>(rMessage.payload);
                    notifyObserversPrintRefund(rppm);
                    break;

                case Methods.RETRIEVE_PAYMENT_RESPONSE:
                    RetrievePaymentResponseMessage rprm = JsonUtils.DeserializeSdk <RetrievePaymentResponseMessage>(rMessage.payload);
                    notifyObserversRetrievePaymentResponse(rprm);
                    break;

                case Methods.GET_PRINTERS_RESPONSE:
                    RetrievePrintersResponseMessage rtrm = JsonUtils.DeserializeSdk <RetrievePrintersResponseMessage>(rMessage.payload);
                    notifyObserversRetrievePrinterResponse(rtrm);
                    break;

                case Methods.PRINT_JOB_STATUS_RESPONSE:
                    PrintJobStatusResponseMessage pjsrm = JsonUtils.DeserializeSdk <PrintJobStatusResponseMessage>(rMessage.payload);
                    notifyObserversRetrievePrintJobStatus(pjsrm);
                    break;

                case Methods.SHOW_RECEIPT_OPTIONS_RESPONSE:
                    ShowReceiptOptionsResponseMessage srorm = JsonUtils.DeserializeSdk <ShowReceiptOptionsResponseMessage>(rMessage.payload);
                    notifyObserverDisplayReceiptOptionsResponse(srorm);
                    break;

                case Methods.CUSTOMER_PROVIDED_DATA_MESSAGE:
                    notifyObserversCustomerProvidedData(JsonUtils.DeserializeSdk <CustomerProvidedDataResponseMessage>(rMessage.payload));
                    break;

                case Methods.PRINT_IMAGE:
                    //Outbound no-op
                    break;

                case Methods.PRINT_TEXT:
                    //Outbound no-op
                    break;

                case Methods.SHOW_ORDER_SCREEN:
                    //Outbound no-op
                    break;

                case Methods.SHOW_PAYMENT_RECEIPT_OPTIONS:
                    //Outbound no-op
                    break;

                case Methods.SHOW_REFUND_RECEIPT_OPTIONS:
                    //Outbound no-op
                    break;

                case Methods.SHOW_CREDIT_RECEIPT_OPTIONS:
                    //Outbound no-op
                    break;

                case Methods.SHOW_THANK_YOU_SCREEN:
                    //Outbound no-op
                    break;

                case Methods.SHOW_WELCOME_SCREEN:
                    //Outbound no-op
                    break;

                case Methods.SIGNATURE_VERIFIED:
                    //Outbound no-op
                    break;

                case Methods.TERMINAL_MESSAGE:
                    //Outbound no-op
                    break;

                case Methods.TX_START:
                    //Outbound no-op
                    break;

                case Methods.VOID_PAYMENT:
                    //Outbound no-op
                    break;

                case Methods.VOID_PAYMENT_RESPONSE:
                    VoidPaymentResponseMessage vprm = JsonUtils.DeserializeSdk <VoidPaymentResponseMessage>(rMessage.payload);
                    notifyObserversPaymentVoided(vprm);
                    break;

                case Methods.CLOSEOUT_REQUEST:
                    //Outbound no-op
                    break;

                case Methods.VAULT_CARD:
                    //Outbound no-op
                    break;

                case Methods.CARD_DATA:
                    //Outbound no-op
                    break;

                case Methods.CLOVER_DEVICE_LOG_REQUEST:
                    //Outbound no-op
                    break;

                default:
                    // Messsage Method not recognized or null: usually rMessage.type == MessageTypes.PING instead of normal Command message
                    if (rMessage.type == MessageTypes.PING)
                    {
                        onPing();
                    }
                    break;
                }
            }
        }
        /// <summary>
        /// This handles parsing the generic message and figuring
        /// out which handler should be used for processing
        /// </summary>
        /// <param name="message">The message.</param>
        public void onMessage(string message)
        {
#if DEBUG
            Console.WriteLine("Received raw message: " + message);
#endif
            //CloverTransportObserver
            // Deserialize the message object to a real object, and figure
            RemoteMessage rMessage = JsonUtils.deserializeSDK <RemoteMessage>(message);
            remoteMessageVersion = Math.Max(remoteMessageVersion, rMessage.version);

            switch (rMessage.method)
            {
            case Methods.BREAK:
                break;

            case Methods.ACK:
                AcknowledgementMessage ackMessage = JsonUtils.deserializeSDK <AcknowledgementMessage>(rMessage.payload);
                notifyObserverAck(ackMessage);
                break;

            case Methods.CASHBACK_SELECTED:
                CashbackSelectedMessage cbsMessage = JsonUtils.deserializeSDK <CashbackSelectedMessage>(rMessage.payload);
                notifyObserversCashbackSelected(cbsMessage);
                break;

            case Methods.DISCOVERY_RESPONSE:
                DiscoveryResponseMessage drMessage = JsonUtils.deserializeSDK <DiscoveryResponseMessage>(rMessage.payload);
                deviceInfo.name   = drMessage.name;
                deviceInfo.serial = drMessage.serial;
                deviceInfo.model  = drMessage.model;
                notifyObserversDiscoveryResponse(drMessage);
                break;

            case Methods.FINISH_CANCEL:
                FinishCancelMessage finishCancelMessage = JsonUtils.deserializeSDK <FinishCancelMessage>(rMessage.payload);
                notifyObserversFinishCancel(finishCancelMessage.requestInfo);
                break;

            case Methods.FINISH_OK:
                FinishOkMessage fokmsg = JsonUtils.deserializeSDK <FinishOkMessage>(rMessage.payload);
                notifyObserversFinishOk(fokmsg);
                break;

            case Methods.KEY_PRESS:
                KeyPressMessage kpm = JsonUtils.deserializeSDK <KeyPressMessage>(rMessage.payload);
                notifyObserversKeyPressed(kpm);
                break;

            case Methods.ORDER_ACTION_RESPONSE:
                break;

            case Methods.PARTIAL_AUTH:
                PartialAuthMessage partialAuth = JsonUtils.deserializeSDK <PartialAuthMessage>(rMessage.payload);
                notifyObserversPartialAuth(partialAuth);
                break;

            case Methods.PAYMENT_VOIDED:
                // this seems to only gets called if a Signature is "Canceled" on the device
                break;

            case Methods.CONFIRM_PAYMENT_MESSAGE:
                setPaymentConfirmationIdle(false);
                ConfirmPaymentMessage confirmPaymentMessage = JsonUtils.deserializeSDK <ConfirmPaymentMessage>(rMessage.payload);
                notifyObserversConfirmPayment(confirmPaymentMessage);
                break;

            case Methods.TIP_ADDED:
                TipAddedMessage tipMessage = JsonUtils.deserializeSDK <TipAddedMessage>(rMessage.payload);
                notifyObserversTipAdded(tipMessage);
                break;

            case Methods.TX_START_RESPONSE:
                TxStartResponseMessage txsrm = JsonUtils.deserializeSDK <TxStartResponseMessage>(rMessage.payload);
                notifyObserversTxStartResponse(txsrm);
                break;

            case Methods.TX_STATE:
                TxStateMessage txStateMsg = JsonUtils.deserializeSDK <TxStateMessage>(rMessage.payload);
                notifyObserversTxState(txStateMsg);
                break;

            case Methods.UI_STATE:
                UiStateMessage uiStateMsg = JsonUtils.deserializeSDK <UiStateMessage>(rMessage.payload);
                notifyObserversUiState(uiStateMsg);
                break;

            case Methods.VERIFY_SIGNATURE:
                paymentRejected = false;
                VerifySignatureMessage vsigMsg = JsonUtils.deserializeSDK <VerifySignatureMessage>(rMessage.payload);
                notifyObserversVerifySignature(vsigMsg);
                break;

            case Methods.REFUND_RESPONSE:
                RefundResponseMessage refRespMsg = JsonUtils.deserializeSDK <RefundResponseMessage>(rMessage.payload);
                notifyObserversRefundPaymentResponse(refRespMsg);
                break;

            case Methods.TIP_ADJUST_RESPONSE:
                TipAdjustResponseMessage tipAdjustMsg = JsonUtils.deserializeSDK <TipAdjustResponseMessage>(rMessage.payload);
                notifyObserversTipAdjusted(tipAdjustMsg);
                break;

            case Methods.REFUND_REQUEST:
                //Outbound no-op
                break;

            case Methods.VAULT_CARD_RESPONSE:
                VaultCardResponseMessage vcrMsg = JsonUtils.deserializeSDK <VaultCardResponseMessage>(rMessage.payload);
                notifyObserversVaultCardResponse(vcrMsg);
                break;

            case Methods.CARD_DATA_RESPONSE:
                ReadCardDataResponseMessage rcdrMsg = JsonUtils.deserializeSDK <ReadCardDataResponseMessage>(rMessage.payload);
                notifyObserversReadCardDataResponse(rcdrMsg);
                break;

            case Methods.CAPTURE_PREAUTH_RESPONSE:
                CapturePreAuthResponseMessage carMsg = JsonUtils.deserializeSDK <CapturePreAuthResponseMessage>(rMessage.payload);
                notifyObserversCapturePreAuthResponse(carMsg);
                break;

            case Methods.CLOSEOUT_RESPONSE:
                CloseoutResponseMessage crMsg = JsonUtils.deserializeSDK <CloseoutResponseMessage>(rMessage.payload);
                notifyObserversCloseoutResponse(crMsg);
                break;

            case Methods.RETRIEVE_PENDING_PAYMENTS_RESPONSE:
                RetrievePendingPaymentsResponseMessage rpprMsg = JsonUtils.deserializeSDK <RetrievePendingPaymentsResponseMessage>(rMessage.payload);
                notifyObserversPendingPaymentsResponse(rpprMsg);
                break;

            case Methods.ACTIVITY_RESPONSE:
                ActivityResponseMessage arm = JsonUtils.deserializeSDK <ActivityResponseMessage>(rMessage.payload);
                notifyObserversActivityResponse(arm);
                break;

            case Methods.ACTIVITY_MESSAGE_FROM_ACTIVITY:
                ActivityMessageFromActivity amfa = JsonUtils.deserializeSDK <ActivityMessageFromActivity>(rMessage.payload);
                notifyObserversActivityMessage(amfa);
                break;

            case Methods.RESET_DEVICE_RESPONSE:
                ResetDeviceResponseMessage rdrm = JsonUtils.deserializeSDK <ResetDeviceResponseMessage>(rMessage.payload);
                notifyObserversDeviceReset(rdrm);
                break;

            case Methods.RETRIEVE_DEVICE_STATUS_RESPONSE:
                RetrieveDeviceStatusResponseMessage rdsrm = JsonUtils.deserializeSDK <RetrieveDeviceStatusResponseMessage>(rMessage.payload);
                notifyObserversRetrieveDeviceStatusResponse(rdsrm);
                break;

            case Methods.DISCOVERY_REQUEST:
                //Outbound no-op
                break;

            case Methods.ORDER_ACTION_ADD_DISCOUNT:
                //Outbound no-op
                break;

            case Methods.ORDER_ACTION_ADD_LINE_ITEM:
                //Outbound no-op
                break;

            case Methods.ORDER_ACTION_REMOVE_LINE_ITEM:
                //Outbound no-op
                break;

            case Methods.ORDER_ACTION_REMOVE_DISCOUNT:
                //Outbound no-op
                break;

            case Methods.PRINT_CREDIT:
                CreditPrintMessage cpm = JsonUtils.deserializeSDK <CreditPrintMessage>(rMessage.payload);
                notifyObserversPrintCredit(cpm);
                break;

            case Methods.PRINT_CREDIT_DECLINE:
                DeclineCreditPrintMessage dcpm = JsonUtils.deserializeSDK <DeclineCreditPrintMessage>(rMessage.payload);
                notifyObserversPrintCreditDecline(dcpm);
                break;

            case Methods.PRINT_PAYMENT:
                PaymentPrintMessage ppm = JsonUtils.deserializeSDK <PaymentPrintMessage>(rMessage.payload);
                notifyObserversPrintPayment(ppm);
                break;

            case Methods.PRINT_PAYMENT_DECLINE:
                DeclinePaymentPrintMessage dppm = JsonUtils.deserializeSDK <DeclinePaymentPrintMessage>(rMessage.payload);
                notifyObserversPrintPaymentDecline(dppm);
                break;

            case Methods.PRINT_PAYMENT_MERCHANT_COPY:
                PaymentPrintMerchantCopyMessage ppmcm = JsonUtils.deserializeSDK <PaymentPrintMerchantCopyMessage>(rMessage.payload);
                notifyObserversPrintMerchantCopy(ppmcm);
                break;

            case Methods.REFUND_PRINT_PAYMENT:
                RefundPaymentPrintMessage rppm = JsonUtils.deserializeSDK <RefundPaymentPrintMessage>(rMessage.payload);
                notifyObserversPrintRefund(rppm);
                break;

            case Methods.RETRIEVE_PAYMENT_RESPONSE:
                RetrievePaymentResponseMessage rprm = JsonUtils.deserializeSDK <RetrievePaymentResponseMessage>(rMessage.payload);
                notifyObserversRetrievePaymentResponse(rprm);
                break;

            case Methods.GET_PRINTERS_RESPONSE:
                RetrievePrintersResponseMessage rtrm = JsonUtils.deserializeSDK <RetrievePrintersResponseMessage>(rMessage.payload);
                notifyObserversRetrievePrinterResponse(rtrm);
                break;

            case Methods.PRINT_JOB_STATUS_RESPONSE:
                PrintJobStatusResponseMessage pjsrm = JsonUtils.deserializeSDK <PrintJobStatusResponseMessage>(rMessage.payload);
                notifyObserversRetrievePrintJobStatus(pjsrm);
                break;

            case Methods.PRINT_IMAGE:
                //Outbound no-op
                break;

            case Methods.PRINT_TEXT:
                //Outbound no-op
                break;

            case Methods.SHOW_ORDER_SCREEN:
                //Outbound no-op
                break;

            case Methods.SHOW_PAYMENT_RECEIPT_OPTIONS:
                //Outbound no-op
                break;

            case Methods.SHOW_REFUND_RECEIPT_OPTIONS:
                //Outbound no-op
                break;

            case Methods.SHOW_CREDIT_RECEIPT_OPTIONS:
                //Outbound no-op
                break;

            case Methods.SHOW_THANK_YOU_SCREEN:
                //Outbound no-op
                break;

            case Methods.SHOW_WELCOME_SCREEN:
                //Outbound no-op
                break;

            case Methods.SIGNATURE_VERIFIED:
                //Outbound no-op
                break;

            case Methods.TERMINAL_MESSAGE:
                //Outbound no-op
                break;

            case Methods.TX_START:
                //Outbound no-op
                break;

            case Methods.VOID_PAYMENT:
                //Outbound no-op
                break;

            case Methods.CLOSEOUT_REQUEST:
                //Outbound no-op
                break;

            case Methods.VAULT_CARD:
                //Outbound no-op
                break;

            case Methods.CARD_DATA:
                //Outbound no-op
                break;
            }
        }
        public override void doTxStart(PayIntent payIntent, Order order, bool suppressTipsOnScreen)
        {
            BackgroundWorker bw = new BackgroundWorker();

            // what to do in the background thread
            bw.DoWork += new DoWorkEventHandler(
                delegate(object o, DoWorkEventArgs args)
            {
                if (payIntent.amount > 0 && payIntent.transactionType == PayIntent.TransactionType.PAYMENT)
                {
                    if (payIntent.amount > 4000 && !suppressTipsOnScreen)
                    {
                        // let's tip
                        notifyObserversUiState(new UiStateMessage(UiState.ADD_TIP, "Customer is tipping...", UiDirection.ENTER, new InputOption[0]));
                        Console.WriteLine("Received UiStateMessage: ADD_TIP Customer is tipping... Enter");
                        Thread.Sleep(1000);
                        notifyObserversUiState(new UiStateMessage(UiState.ADD_TIP, "Customer is tipping...", UiDirection.EXIT, new InputOption[0]));
                        Console.WriteLine("Received UiStateMessage: ADD_TIP Customer is tipping... Exit");
                        payIntent.tipAmount = (long)(payIntent.amount * 0.1f);
                    }
                    notifyObserversUiState(new UiStateMessage(UiState.START, "Customer is choosing payment.", UiDirection.ENTER, new InputOption[0]));
                    Console.WriteLine("Received UiStateMessage: START Customer is choosing payment. Enter");
                    Thread.Sleep(1000);
                    notifyObserversUiState(new UiStateMessage(UiState.START, "Customer is choosing payment.", UiDirection.EXIT, new InputOption[0]));
                    Console.WriteLine("Received UiStateMessage: START Customer is choosing payment. Exit");
                    notifyObserversUiState(new UiStateMessage(UiState.PROCESSING, "Processing...", UiDirection.ENTER, new InputOption[0]));
                    Console.WriteLine("Received UiStateMessage: PROCESSING Processing... Enter");
                    Thread.Sleep(1000);
                    notifyObserversUiState(new UiStateMessage(UiState.PROCESSING, "Processing...", UiDirection.EXIT, new InputOption[0]));
                    Console.WriteLine("Received UiStateMessage: PROCESSING Processing... Exit");

                    if (payIntent.amount < 5000) // less than 50
                    {
                        Payment payment     = new Payment();
                        payment.amount      = payIntent.amount;
                        payment.id          = Guid.NewGuid().ToString();
                        payment.employee    = new Reference();
                        payment.employee.id = Guid.NewGuid().ToString();
                        payment.order       = new Reference();
                        if (order != null)
                        {
                            payment.order.id = order.id;
                        }
                        FinishOkMessage okMsg         = new FinishOkMessage();
                        payment.cardTransaction       = new CardTransaction();
                        payment.cardTransaction.last4 = "0123";
                        payment.cardTransaction.token = "1234567890123456";
                        TempObjectMap.Add(payment.id, payment);
                        okMsg.payment = payment;
                        notifyObserversFinishOk(okMsg);
                        Console.WriteLine("Received FINISH_OK: " + okMsg.payment);
                    }
                    else if (payIntent.amount > 10000 && payIntent.amount < 15000)
                    {
                        // if payment without tip is $100-$150 then simulate cancel transaction
                        notifyObserversFinishCancel();
                        Console.WriteLine("Received FinishCancel Message: ");
                    }
                    else
                    {
                        notifyObserversUiState(new UiStateMessage(UiState.ADD_SIGNATURE, "Waiting for signature...", UiDirection.ENTER, new InputOption[0]));
                        Console.WriteLine("Received UiStateMessage: ADD_SIGNATURE Waiting for Signature... Enter");
                        Thread.Sleep(3000);
                        notifyObserversUiState(new UiStateMessage(UiState.ADD_SIGNATURE, "Waiting for signature...", UiDirection.EXIT, new InputOption[0]));
                        Console.WriteLine("Received UiStateMessage: ADD_SIGNATURE Waiting for Signature... Exit");

                        Signature2 sig = JsonUtils.deserialize <Signature2>("{\"strokes\":[{\"points\":[{\"x\":174,\"y\":341},{\"x\":177,\"y\":338},{\"x\":183,\"y\":330},{\"x\":189,\"y\":323},{\"x\":200,\"y\":313},{\"x\":208,\"y\":305},{\"x\":217,\"y\":296},{\"x\":230,\"y\":284},{\"x\":241,\"y\":271},{\"x\":252,\"y\":257},{\"x\":261,\"y\":243},{\"x\":267,\"y\":233},{\"x\":273,\"y\":220},{\"x\":277,\"y\":206},{\"x\":279,\"y\":196},{\"x\":278,\"y\":182},{\"x\":275,\"y\":173},{\"x\":272,\"y\":164},{\"x\":267,\"y\":156},{\"x\":262,\"y\":151},{\"x\":252,\"y\":144},{\"x\":244,\"y\":141},{\"x\":235,\"y\":141},{\"x\":226,\"y\":144},{\"x\":217,\"y\":148},{\"x\":209,\"y\":154},{\"x\":202,\"y\":162},{\"x\":197,\"y\":171},{\"x\":195,\"y\":183},{\"x\":193,\"y\":195},{\"x\":195,\"y\":209},{\"x\":202,\"y\":222},{\"x\":208,\"y\":231},{\"x\":219,\"y\":241},{\"x\":231,\"y\":248},{\"x\":242,\"y\":253},{\"x\":253,\"y\":255},{\"x\":271,\"y\":256},{\"x\":285,\"y\":254},{\"x\":302,\"y\":252},{\"x\":311,\"y\":249},{\"x\":320,\"y\":245},{\"x\":329,\"y\":241},{\"x\":337,\"y\":236},{\"x\":344,\"y\":233},{\"x\":349,\"y\":231},{\"x\":352,\"y\":229},{\"x\":351,\"y\":234},{\"x\":350,\"y\":240},{\"x\":347,\"y\":247},{\"x\":343,\"y\":255},{\"x\":336,\"y\":267},{\"x\":327,\"y\":277},{\"x\":316,\"y\":287},{\"x\":302,\"y\":296},{\"x\":283,\"y\":301},{\"x\":264,\"y\":304},{\"x\":244,\"y\":305},{\"x\":227,\"y\":301},{\"x\":213,\"y\":298},{\"x\":204,\"y\":292},{\"x\":195,\"y\":287},{\"x\":190,\"y\":283},{\"x\":187,\"y\":280},{\"x\":193,\"y\":284},{\"x\":200,\"y\":288},{\"x\":214,\"y\":294},{\"x\":232,\"y\":303},{\"x\":251,\"y\":312},{\"x\":272,\"y\":320},{\"x\":292,\"y\":328},{\"x\":313,\"y\":332},{\"x\":333,\"y\":334},{\"x\":351,\"y\":332},{\"x\":368,\"y\":326},{\"x\":378,\"y\":317},{\"x\":390,\"y\":307},{\"x\":400,\"y\":300},{\"x\":407,\"y\":292},{\"x\":412,\"y\":284},{\"x\":415,\"y\":275},{\"x\":416,\"y\":268},{\"x\":415,\"y\":261},{\"x\":410,\"y\":259},{\"x\":401,\"y\":261},{\"x\":393,\"y\":266},{\"x\":381,\"y\":275},{\"x\":376,\"y\":282},{\"x\":372,\"y\":295},{\"x\":371,\"y\":304},{\"x\":375,\"y\":312},{\"x\":372,\"y\":318},{\"x\":387,\"y\":326},{\"x\":396,\"y\":329},{\"x\":404,\"y\":330},{\"x\":412,\"y\":328},{\"x\":419,\"y\":322},{\"x\":424,\"y\":314},{\"x\":426,\"y\":305},{\"x\":424,\"y\":294},{\"x\":419,\"y\":284},{\"x\":415,\"y\":278},{\"x\":405,\"y\":270},{\"x\":398,\"y\":267},{\"x\":393,\"y\":265},{\"x\":391,\"y\":266},{\"x\":394,\"y\":273},{\"x\":399,\"y\":278},{\"x\":410,\"y\":286},{\"x\":426,\"y\":292},{\"x\":444,\"y\":295},{\"x\":463,\"y\":294},{\"x\":477,\"y\":292},{\"x\":486,\"y\":287},{\"x\":495,\"y\":282},{\"x\":501,\"y\":276},{\"x\":507,\"y\":270},{\"x\":511,\"y\":265},{\"x\":513,\"y\":260},{\"x\":508,\"y\":260},{\"x\":502,\"y\":263},{\"x\":495,\"y\":268},{\"x\":489,\"y\":276},{\"x\":485,\"y\":285},{\"x\":482,\"y\":293},{\"x\":485,\"y\":300},{\"x\":489,\"y\":304},{\"x\":494,\"y\":308},{\"x\":501,\"y\":308},{\"x\":507,\"y\":304},{\"x\":512,\"y\":300},{\"x\":517,\"y\":294},{\"x\":518,\"y\":289},{\"x\":520,\"y\":283},{\"x\":523,\"y\":279},{\"x\":523,\"y\":276},{\"x\":525,\"y\":274},{\"x\":530,\"y\":272},{\"x\":538,\"y\":270},{\"x\":548,\"y\":268},{\"x\":563,\"y\":267},{\"x\":580,\"y\":267},{\"x\":590,\"y\":266},{\"x\":600,\"y\":265},{\"x\":609,\"y\":264},{\"x\":616,\"y\":263},{\"x\":622,\"y\":262},{\"x\":626,\"y\":261},{\"x\":622,\"y\":262},{\"x\":613,\"y\":264},{\"x\":597,\"y\":270},{\"x\":582,\"y\":279},{\"x\":568,\"y\":290},{\"x\":561,\"y\":299},{\"x\":557,\"y\":306},{\"x\":559,\"y\":315},{\"x\":565,\"y\":321},{\"x\":572,\"y\":326},{\"x\":583,\"y\":325},{\"x\":600,\"y\":316},{\"x\":614,\"y\":304},{\"x\":625,\"y\":289},{\"x\":631,\"y\":269},{\"x\":634,\"y\":247},{\"x\":633,\"y\":222},{\"x\":630,\"y\":196},{\"x\":627,\"y\":170},{\"x\":626,\"y\":150},{\"x\":624,\"y\":134},{\"x\":625,\"y\":125},{\"x\":626,\"y\":117},{\"x\":627,\"y\":111},{\"x\":628,\"y\":109},{\"x\":629,\"y\":115},{\"x\":632,\"y\":129},{\"x\":638,\"y\":152},{\"x\":645,\"y\":177},{\"x\":654,\"y\":205},{\"x\":663,\"y\":235},{\"x\":674,\"y\":264},{\"x\":684,\"y\":288},{\"x\":693,\"y\":304},{\"x\":697,\"y\":313},{\"x\":701,\"y\":314}]}],\"height\":666,\"width\":799}");

                        // send signature...
                        Payment payment     = new Payment();
                        payment.amount      = payIntent.amount;
                        payment.id          = Guid.NewGuid().ToString();
                        payment.employee    = new Reference();
                        payment.employee.id = Guid.NewGuid().ToString();
                        payment.order       = new Reference();
                        if (order != null)
                        {
                            payment.order.id = order.id;
                        }

                        if (payIntent.tipAmount.HasValue)
                        {
                            payment.tipAmount = payIntent.tipAmount.Value;
                        }
                        TempObjectMap.Add(payment.id, payment);
                        VerifySignatureMessage msg = new VerifySignatureMessage();
                        msg.signature = sig;
                        msg.payment   = payment;
                        notifyObserversVerifySignature(msg);
                        Console.WriteLine("Received VerifySignatureMessage: " + JsonUtils.serialize(msg));
                    }
                }
                else if (payIntent.amount < 0 && payIntent.transactionType == PayIntent.TransactionType.CREDIT)
                {
                    notifyObserversUiState(new UiStateMessage(UiState.START, "Customer is choosing payment.", UiDirection.ENTER, new InputOption[0]));
                    Console.WriteLine("Received UiStateMessage: START Customer is choosing payment... Enter");
                    Thread.Sleep(1000);
                    notifyObserversUiState(new UiStateMessage(UiState.START, "Customer is choosing payment.", UiDirection.EXIT, new InputOption[0]));
                    Console.WriteLine("Received UiStateMessage: START Customer is choosing payment... Exit");
                    notifyObserversUiState(new UiStateMessage(UiState.PROCESSING, "Processing...", UiDirection.ENTER, new InputOption[0]));
                    Console.WriteLine("Received UiStateMessage: PROCESSING Processing... Enter");
                    Thread.Sleep(3000);
                    notifyObserversUiState(new UiStateMessage(UiState.PROCESSING, "Processing...", UiDirection.EXIT, new InputOption[0]));
                    Console.WriteLine("Received UiStateMessage: PROCESSING Processing... Exit");
                    notifyObserversUiState(new UiStateMessage(UiState.RECEIPT_OPTIONS, "Customer is selecting receipt type.", UiDirection.ENTER, new InputOption[0]));
                    Console.WriteLine("Received UiStateMessage: RECEIPT_OPTIONS Customer is selecting receipt type. Enter");
                    Thread.Sleep(3000);
                    notifyObserversUiState(new UiStateMessage(UiState.RECEIPT_OPTIONS, "Customer is selecting receipt type.", UiDirection.EXIT, new InputOption[0]));
                    Console.WriteLine("Received UiStateMessage: RECEIPT_OPTIONS Customer is selecting receipt type. Exit");

                    Credit credit                = new Credit();
                    credit.amount                = payIntent.amount;
                    credit.id                    = Guid.NewGuid().ToString();
                    FinishOkMessage okMsg        = new FinishOkMessage();
                    credit.cardTransaction       = new CardTransaction();
                    credit.cardTransaction.last4 = "0123";
                    okMsg.credit                 = credit;
                    TempObjectMap.Add(credit.id, credit);
                    notifyObserversFinishOk(okMsg);
                    Console.WriteLine("Received FinishOkMessage: FINISH_OK");
                }
            });
            bw.RunWorkerAsync();
        }
 public void notifyObserversFinishOk(FinishOkMessage msg)
 {
     foreach (ICloverDeviceObserver observer in deviceObservers)
     {
         if (msg.payment != null)
         {
             observer.onFinishOk(msg.payment, msg.signature);
         }
         else if (msg.credit != null)
         {
             observer.onFinishOk(msg.credit);
         }
         else if (msg.refund != null)
         {
             observer.onFinishOk(msg.refund);
         }
         else
         {
             Console.WriteLine("Don't know what to do with this Finish OK message: " + JsonUtils.serialize(msg));
         }
     }
 }