function Step3MigrateVideoMember($merchantAccountId)
{
    $uniqueValue = $merchantAccountId;
    //Step 3
    //Assume that this subscription is for Video access for one year, and was paid in full 6 months ago.
    //As such it will be up for renewal in 6 months.
    //Generally, these dates are retrieved from your datastore.
    $sixmonthsagoPT = new \DateTime('-6 months', new \DateTimeZone('America/Los_Angeles'));
    $sixmonthsfromnowPT = new \DateTime('6 months', new \DateTimeZone('America/Los_Angeles'));
    $dateActiveSubscriptionPeriodPaidInFull = $sixmonthsagoPT->format(DateTime::ATOM);
    $dateActiveSubscriptionPeriodUpForRenewal = $sixmonthsfromnowPT->format(DateTime::ATOM);
    $billPlan = new BillingPlan();
    $product = new Product();
    // Generally, the billing plan and productid will be provided in your datastore.
    // These objects need to exist in CashBox prior to migration.
    $merchantBillingPlanId = 'OneYearSubOneYearRecurring';
    $merchantProductId = 'Video';
    $billPlan->setMerchantBillingPlanId($merchantBillingPlanId);
    $product->setMerchantProductId($merchantProductId);
    //To save a soap call, you can use sparse objects.
    $account = new Account();
    $account->merchantAccountId = $merchantAccountId;
    // Assuming merchantPaymentMethodId is the same value as the merchantAccountId.
    $merchantPaymentMethodId = $merchantAccountId;
    $paymentMethod = new PaymentMethod();
    $paymentMethod->merchantPaymentMethodId = $merchantPaymentMethodId;
    //If you don't have the address VID, then set migrationtransaction shippingaddress to null.
    $address = null;
    //    // If you want to fetch the account by making a soap call to CashBox...
    //    // This is a soap call to CashBox.
    //    $fetchedAccount = get_account_by_merchantAccountId($merchantAccountId);
    //
    //    // Only use sparse object, so all data members are not over-written.
    //    $account->merchantAccountId = $fetchedAccount->merchantAccountId;
    //    $fetchedPaymentMethod = $account->paymentMethods[0];
    //
    //    // Only use sparse object, so all data members are not over-written.
    //    $paymentMethod->merchantPaymentMethodId = $fetchedPaymentMethod->merchantPaymentMethodId;
    $paymentMethodType = 'CreditCard';
    $currency = 'USD';
    $lastPaidPrice = '10.00';
    $useZeroUnlessYouKnowDifferent = 0;
    $paymentProcessor = 'Paymentech';
    $transactionType = 'Recurring';
    $authCode = '000';
    $capturedStatus = 'Captured';
    $txItemType = 'RecurringCharge';
    $txItemName = $merchantProductId . ':' . $merchantBillingPlanId;
    // This paymentProcessorTransactionId makes the transaction refundable if migrating from Litle (Vantiv) into Litle.
    $paymentProcessorTransactionId = 'RetrievedIdFromLegacyBillingPaymentProcessor';
    // Assume campaigns were not used when creating this Autobill.
    // Alternatively, consider specifying campaign on the AutoBillItem if necessary.
    $item = new AutoBillItem();
    $item->setIndex(0);
    $item->setAddedDate($dateActiveSubscriptionPeriodPaidInFull);
    $item->setMerchantAutoBillItemId(get_unique_value());
    $item->setProduct($product);
    $autobill = new AutoBill();
    // No need to set payment method on Autobill as it will be inherited from the Account.
    $autobill->setAccount($account);
    $autobill->setItems(array($item));
    $autobill->setBillingPlan($billPlan);
    $autobill->setCurrency($currency);
    $autobill->setCustomerAutoBillName($uniqueValue);
    $autobill->setMerchantAutoBillId($uniqueValue);
    $autobill->setStartTimestamp($dateActiveSubscriptionPeriodPaidInFull);
    // For this example, we assume one transaction item with a price equal to the entire migration transaction amount.
    $txItemA = new MigrationTransactionItem();
    $txItemA->setItemType($txItemType);
    $txItemA->setName($txItemName);
    $txItemA->setPrice($lastPaidPrice);
    $txItemA->setServicePeriodStartDate($dateActiveSubscriptionPeriodPaidInFull);
    $txItemA->setServicePeriodEndDate($dateActiveSubscriptionPeriodUpForRenewal);
    // It is recommended Sku equals the merchantProductId of the Product set on the Autobill.
    $txItemA->setSku($merchantProductId);
    $creditCardStatusA = new TransactionStatusCreditCard();
    $statusLogA = new TransactionStatus();
    // AuthCode is the code for a transaction successfully run through the payment processor.
    $creditCardStatusA->setAuthCode($authCode);
    $statusLogA->setCreditCardStatus($creditCardStatusA);
    $statusLogA->setPaymentMethodType($paymentMethodType);
    $statusLogA->setStatus($capturedStatus);
    $statusLogA->setTimestamp($dateActiveSubscriptionPeriodPaidInFull);
    $merchantTransactionId = $uniqueValue;
    fail_if_merchant_transaction_id_too_long($merchantTransactionId);
    // Assume sales tax calculated refunds not in scope in this example.
    // If they were, consider setting salesTaxAddress and tax migration transaction items.
    // Assume we are only migrating the last transaction used to pay for the Autobill.
    // If in scope, you have the option to migrate more than one.
    $migrationTransaction = new MigrationTransaction();
    $migrationTransaction->setAccount($account);
    // Set to 21 characters or less, or you will not be able to refund against this.
    $migrationTransaction->setMerchantTransactionId($merchantTransactionId);
    // Total migration transaction amount must equal sum of tx items.
    $migrationTransaction->setAmount($lastPaidPrice);
    // It is recommended that AutoBillCycle is set to the number of times the Autobill has renewed.
    // Make a best effort guess if exact number is unknown.
    // This will help with CashBox Reviews to determine metrics such as Lifetime Value (LTV).
    $migrationTransaction->setAutoBillCycle($useZeroUnlessYouKnowDifferent);
    $migrationTransaction->setBillingDate($dateActiveSubscriptionPeriodPaidInFull);
    // If the billing plan is modified, then the billing plan cycle resets to 0.
    // In general, if the billing has not been modified, this value will be the same as the AutoBill Cycle.
    $migrationTransaction->setBillingPlanCycle($useZeroUnlessYouKnowDifferent);
    $migrationTransaction->setCurrency($currency);
    $migrationTransaction->setPaymentProcessor($paymentProcessor);
    $migrationTransaction->setMerchantBillingPlanId($merchantBillingPlanId);
    $migrationTransaction->setMigrationTransactionItems(array($txItemA));
    $migrationTransaction->setPaymentMethod($paymentMethod);
    $migrationTransaction->setShippingAddress($address);
    $migrationTransaction->setStatusLog(array($statusLogA));
    $migrationTransaction->setType($transactionType);
    $migrationTransaction->setPaymentProcessorTransactionId($paymentProcessorTransactionId);
    //    Division ID mapping:
    //    123456 - Standard Subscription  [Default]
    //    123457 - Premium Subscription
    // CashBox merchant configuration will be configured to route automatically based on a name value pair.
    // Confirm with your Deployment Consultant the values matching the merchant configuration.
    $divisionId = new NameValuePair();
    $divisionId->setName('vin:Division');
    $divisionId->setValue('Premium Subscription');
    $migrationTransaction->setNameValues(array($divisionId));
    //$divisionNumber='123456';
    //$migrationTransaction->setDivisionNumber($divisionNumber);
    $srd = '';
    $response = $autobill->migrate($srd, $dateActiveSubscriptionPeriodUpForRenewal, array($migrationTransaction));
    // Log soap id for each API call.
    //    $log->addDebug('Method = Autobill.migrate' . PHP_EOL);
    //    $log->addDebug('Soap Id = ' . $response['data']->return->soapId . PHP_EOL);
    //    $log->addDebug('Return Code = ' . $response['returnCode'] . PHP_EOL);
    //    $log->addDebug('Return String = ' . $response['returnString'] . PHP_EOL);
    if ($response['returnCode'] == 200) {
        print "Call succeeded" . PHP_EOL;
    } else {
        print "Call failed" . PHP_EOL;
    }
    return $response;
}
function hoaTransactionAuthThenCapture()
{
    $uniqueValue = get_unique_value();
    $merchantAccountId = 'account-' . $uniqueValue;
    $merchantTransactionId = 't-' . $uniqueValue;
    if (fail_if_merchant_transaction_id_too_long($merchantTransactionId)) {
        return;
    }
    $merchantPaymentMethodId = 'pm-' . $uniqueValue;
    $creditCardAccount = '5454541111111111';
    $paymentType = 'CreditCard';
    $cvn = '111';
    $exp = '201801';
    $email = get_unique_value() . '@nomail.com';
    $successUrl = 'http://good.com';
    $errorUrl = 'http://bad.com';
    $HOAmethod = 'Transaction_Auth';
    $HOAurl = 'https://secure.prodtest.sj.vindicia.com/vws';
    $HOAversion = '5.0';
    $ipAddress = '127.0.0.1';
    $name = 'John Vindicia';
    $addr1 = '303 Twin Dolphin Drive';
    $city = 'Redwood City';
    $district = 'CA';
    $postalCode = '94065';
    $country = 'US';
    #------------------------------------------------------------
    #-Step 1-
    #-Step 1- Initialize the WebSession before the PaymentMethod
    #-Step 1- form is displayed to the user
    #-Step 1-
    #
    # Create a new WebSession object
    $webSession = new WebSession();
    # Set the WebSession parameters
    $webSession->setReturnURL($successUrl);
    $webSession->setErrorURL($errorUrl);
    $webSession->setIpAddress($ipAddress);
    $webSession->setMethod($HOAmethod);
    $webSession->setVersion($HOAversion);
    #------------------------------------------------------------
    # Set PrivateFormValues. These are hidden fields in the POST
    # that we want to protect from hacking. If the value in the
    # POST does not match the value set during initialization,
    # the WebSession.finalize will fail
    //    $account_VID = $account->VID;
    //
    //    $nameVals[0] = new NameValuePair();
    //    $nameVals[0]->setName('Account_VID');
    //    $nameVals[0]->setValue($account_VID); // so that we can use the existing account
    $tx_id = new NameValuePair();
    $tx_id->setName('vin_Transaction_merchantTransactionId');
    $tx_id->setValue($merchantTransactionId);
    // so that we can use the existing account
    # Your ID for this user
    $acct_id = new NameValuePair();
    $acct_id->setName("vin_Account_merchantAccountId");
    $acct_id->setValue($merchantAccountId);
    # Your ID for this PaymentMethod
    $paym_id = new NameValuePair();
    $paym_id->setName("vin_PaymentMethod_merchantPaymentMethodId");
    $paym_id->setValue($merchantPaymentMethodId);
    $pmt_type = new NameValuePair();
    $pmt_type->setName("vin_PaymentMethod_type");
    $pmt_type->setValue($paymentType);
    # Add the PrivateFormValues to the WebSession
    $webSession->setPrivateFormValues(array($tx_id, $acct_id, $paym_id, $pmt_type));
    #------------------------------------------------------------
    # Set any parameters specific for the Method we are
    # calling in the WebSession.
    #
    $minChargebackProbability = new NameValuePair();
    $minChargebackProbability->setName("Transaction_Auth_minChargebackProbability");
    $minChargebackProbability->setValue("70");
    $dryRun = new NameValuePair();
    $dryRun->setName("Transaction_Auth_dryRun");
    $dryRun->setValue("false");
    $sendEmailNotification = new NameValuePair();
    $sendEmailNotification->setName("Transaction_Auth_sendEmailNotification");
    $sendEmailNotification->setValue("true");
    // Transaction_Auth takes in one more parameter - campaignCode
    // We can collect campaign code from the payment form and set
    // prior to WebSession.Finalize, or pass it in here prior to WebSession.Initialize.
    $campaign = 'CampaignXYZ';
    //    $campaignCodeNVP = new NameValuePair();
    //    $campaignCodeNVP->setName("Transaction_Auth_campaignCode");
    //    $campaignCodeNVP->setValue($campaign);
    $webSession->setMethodParamValues(array($sendEmailNotification, $minChargebackProbability, $dryRun));
    # Initialize the WebSession
    #
    $response = $webSession->initialize();
    # Check to see that the initialize succeeded
    #
    if ($response['returnCode'] == 200) {
        # The VID of the WebSession object serves as session id
        #
        $vin_WebSession_vid = $response['data']->session->getVID();
    } else {
        print $response;
        return;
    }
    #------------------------------------------------------------
    #-Step 2-
    #-Step 2- This is the payment method FORM and the HOA POST
    #-Step 2-
    # Fields on the checkout FORM
    # User supplied input
    //    $post['vin_PaymentMethod_merchantPaymentMethodId'] =
    //                $merchantPaymentMethodId;
    $post['vin_PaymentMethod_accountHolderName'] = $post['vin_PaymentMethod_billingAddress_name'] = $name;
    $post['vin_PaymentMethod_billingAddress_addr1'] = $addr1;
    $post['vin_PaymentMethod_billingAddress_city'] = $city;
    $post['vin_PaymentMethod_billingAddress_district'] = $district;
    $post['vin_PaymentMethod_billingAddress_postalCode'] = $postalCode;
    $post['vin_PaymentMethod_billingAddress_country'] = $country;
    $post['vin_Account_emailAddress'] = $email;
    $post['vin_PaymentMethod_creditCard_account'] = $creditCardAccount;
    $post['vin_PaymentMethod_creditCard_expirationDate'] = $exp;
    $post['vin_PaymentMethod_nameValues_cvn'] = $cvn;
    $post['vin_Transaction_transactionItems_0_sku'] = 'Item 1';
    $post['vin_Transaction_transactionItems_0_name'] = 'Item 1 Description';
    $post['vin_Transaction_transactionItems_0_price'] = '99';
    $post['vin_Transaction_transactionItems_0_quantity'] = '1';
    # Hidden fields in the checkout FORM
    #
    $post['vin_WebSession_vid'] = $vin_WebSession_vid;
    # Copy the BillingAddress to the ShippingAddress to improve
    # Chargeback dispute success. Visa will deny disputed Chargeback
    # for many reasons. A missing ShippingAddress, even though there
    # is nothing being shipped, is commonly one of those reasons.
    # This can be done with JavaScript on the checkout form.
    #
    $post['vin_Account_name'] = $post['vin_PaymentMethod_billingAddress_name'];
    $post['vin_Account_shippingAddress_name'] = $post['vin_PaymentMethod_billingAddress_name'];
    $post['vin_Account_shippingAddress_addr1'] = $post['vin_PaymentMethod_billingAddress_addr1'];
    $post['vin_Account_shippingAddress_city'] = $post['vin_PaymentMethod_billingAddress_city'];
    $post['vin_Account_shippingAddress_district'] = $post['vin_PaymentMethod_billingAddress_district'];
    $post['vin_Account_shippingAddress_county'] = $post['vin_PaymentMethod_billingAddress_county'];
    $post['vin_Account_shippingAddress_postalCode'] = $post['vin_PaymentMethod_billingAddress_postalCode'];
    $post['vin_Account_shippingAddress_country'] = $post['vin_PaymentMethod_billingAddress_country'];
    $post['vin_Account_shippingAddress_phone'] = $post['vin_PaymentMethod_billingAddress_phone'];
    // If you have a Campaign Code form value...
    //$post['Transaction_Auth_campaignCode'] = $campaign;
    # Create the curl command line for exec by looping through the
    # $post array
    #
    $curlopts = "";
    foreach ($post as $name => $value) {
        $curlopts .= " --data-urlencode {$name}=\"{$value}\"";
    }
    # Do the POST
    #
    exec("curl -s {$curlopts} " . $HOAurl, $curlout, $curlret);
    #-Step 3-----------------------------------------------------
    #-Step 3-
    #-Step 3- This code should be on the returnURL page
    #-Step 3-
    #-Step 3- Nothing has been committed until the WebSession gets
    #-Step 3- finalized. This is done in the returnURL page code. For
    #-Step 3- example, the returnURL is a confirmation page and when
    #-Step 3- the user clicks a confirmation button the form action
    #-Step 3- is a page that performs all the actual finalize steps.
    #-Step 3-
    #------------------------------------------------------------
    # This is only necessary for this CLI implementation.
    #
    # Flatten the output from exec so we can search it. The response
    # from a successful HOA POST should be a 302 page that contains
    # our returnURL with the WebSessionVID as the query string.
    #
    if (php_sapi_name() == "cli") {
        $curlresp = implode("\n", $curlout);
    }
    #
    #------------------------------------------------------------
    # For CLI, use the WebSessionId we stored in the POST values
    # for curl. For everything else, retrieve the WebSessionId
    # from the URL query string on the redirect to the returnURL
    #
    if (php_sapi_name() == "cli") {
        $session_id = $post['vin_WebSession_vid'];
    } else {
        $session_id = $_GET['session_id'];
    }
    $campaignCode = $post['Transaction_Auth_campaignCode'];
    if ($campaignCode != null) {
        $fetchedWebSession = new WebSession();
        $response = $fetchedWebSession->fetchByVid($session_id);
        $response_object = $response['data'];
        $return_code = $response['returnCode'];
        $websession = $response_object->session;
        if ($return_code != "200" || $websession->apiReturn->returnCode != "200") {
            print $response;
        }
    }
    $webSession = new WebSession();
    $webSession->setVid($session_id);
    if ($campaignCode != null) {
        $campaignCodeNVP = new NameValuePair();
        $campaignCodeNVP->setName("Transaction_Auth_campaignCode");
        $campaignCodeNVP->setValue($campaignCode);
        $webSession->setMethodParamValues(array($campaignCodeNVP));
    }
    $response = $webSession->finalize();
    if ($response['returnCode'] != '200') {
        print $response['data']->session->apiReturn->returnCode . PHP_EOL;
        print $response['data']->session->apiReturn->returnString . PHP_EOL;
    } else {
        print "returnCode=" . $response['data']->session->apiReturn->returnCode . PHP_EOL;
        print "returnString=" . $response['data']->session->apiReturn->returnString . PHP_EOL;
        if ($response['data']->session->apiReturn->returnCode == "200") {
            $returnTransaction = $response['data']->session->apiReturnValues->transactionAuth->transaction;
            if ($returnTransaction->statusLog[0]->status == 'Authorized') {
                print "Transaction approved\n";
                $captureTransaction = new Transaction();
                $response = $captureTransaction->capture(array($returnTransaction));
                print "returnCode=" . $response['returnCode'] . PHP_EOL;
                print "returnString=" . $response['returnString'] . PHP_EOL;
                if ($response['returnCode'] == 200) {
                    $captureResults = $response['data']->results;
                    foreach ($captureResults as $captureResult) {
                        if ($captureResult->returnCode == 200) {
                            print "Transaction with id " . $captureResult->merchantTransactionId . " was successfully captured";
                        } else {
                            print "Transaction was not successfully captured. ReturnCode=" . $captureResult->returnCode;
                        }
                    }
                } else {
                    print "Transactions were not successfully captured. ReturnCode=" . $response['returnCode'];
                }
            } else {
                if ($returnTransaction->statusLog[0]->status == 'Cancelled') {
                    print "Transaction not approved \n";
                    print "Reason code is: ";
                    print $returnTransaction->statusLog[0]->creditCardStatus->authCode;
                    print "\n";
                } else {
                    print "Error: Unexpected transaction status\n";
                }
            }
        } else {
            if ($response['data']->session->apiReturn->returnCode = "202") {
                print "Transaction cannot be processed due to taxes being temporarily unavailable\n";
            } else {
                if ($response['data']->session->apiReturn->returnCode == "400") {
                    print "Transaction cannot be processed due to data validation error\n";
                } else {
                    if ($response['data']->session->apiReturn->returnCode == "402") {
                        print "Transaction cannot be processed due to transaction error\n";
                    } else {
                        if ($response['data']->session->apiReturn->returnCode = "403") {
                            print "Transaction cannot be processed due to high fraud potential\n";
                        } else {
                            if ($response['data']->session->apiReturn->returnCode = "406") {
                                print "Transaction cannot be processed due to Chargeback risk score being higher than minChargebackProbability\n";
                            } else {
                                if ($response['data']->session->apiReturn->returnCode = "407") {
                                    print "Transaction cannot be processed due to Failed AVS policy evaluation\n";
                                } else {
                                    if ($response['data']->session->apiReturn->returnCode = "408") {
                                        print "Transaction cannot be processed due to Failed CVN policy evaluation\n";
                                    } else {
                                        print "Error while making call to Vindicia CashBox\n";
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}