Working IPN Handler with Parallel Payments – PayPal Adaptive Payments

Hey everyone,

Just a dummy implementation of a Parallel Payment and an accompanying IPN Handler using the C#/.NET SDK. Feel free to use it however you like.

//Handles PayPal IPN
        public String IPN()
        {
            //Post back to either sandbox or live
            string strSandbox = "https://www.sandbox.paypal.com/cgi-bin/webscr";
            //string strLive = "https://www.paypal.com/cgi-bin/webscr";
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(strSandbox);

            ////Set values for the request back
            req.Method = "POST";
            req.ContentType = "application/x-www-form-urlencoded";
            byte[] param = Request.BinaryRead(Request.ContentLength);
            string strRequest = Encoding.ASCII.GetString(param);
            strRequest += "&cmd=_notify-validate";
            req.ContentLength = strRequest.Length;

            //Send the request to PayPal and get the response
            StreamWriter streamOut = new StreamWriter(req.GetRequestStream(), System.Text.Encoding.ASCII);
            streamOut.Write(strRequest);
            streamOut.Close();
            StreamReader streamIn = new StreamReader(req.GetResponse().GetResponseStream());
            string strResponse = streamIn.ReadToEnd();
            streamIn.Close();

            if (strResponse == "VERIFIED")
            {
                //check the payment_status is Completed
                //check that txn_id has not been previously processed
                //check that receiver_email is your Primary PayPal email
                //check that payment_amount/payment_currency are correct
                //process payment
            }
            else if (strResponse == "INVALID")
            {
                //log for manual investigation
            }
            else
            {
                //log response/ipn data for manual investigation
            }


            return "";
        }

        //Pay for an order
        public void Pay(int OrderId)
        {
            RequestEnvelope envelopeRequest = new RequestEnvelope();
            envelopeRequest.errorLanguage = "en_US";
            PaySample paySample = new PaySample();
           
            List listReceiver = new List();
            // Amount to be credited to the receiver's account
            Receiver receiverA = new Receiver(Convert.ToDecimal("4.00"));

            // A receiver's email address
            receiverA.email = "test_buyer1@learnerlessons.com.au";
            listReceiver.Add(receiverA);

            // Amount to be credited to the receiver's account
            Receiver receiverB = new Receiver(Convert.ToDecimal("2.00"));

            // A receiver's email address
            receiverB.email = "test_buyer2@learnerlessons.com.au";
            listReceiver.Add(receiverB);

            ReceiverList receiverList = new ReceiverList(listReceiver);

            PayRequest requestPay = new PayRequest(envelopeRequest, "PAY", "http://localhost:53034/orders/cancel", "AUD", receiverList, "http://localhost:53034/orders/return");
            requestPay.reverseAllParallelPaymentsOnError = true;
            requestPay.ipnNotificationUrl = "http://123.123.123.123/Orders/IPN";

            //Send request to paypal, retrieve payKey
            PayResponse payResponse = paySample.PayAPIOperations(requestPay);

            Response.Redirect("https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_ap-payment&paykey=" + payResponse.payKey);
        }

Configuring Custom Settings – PayPal C# SDK

Hey everyone,

I’ve been mucking around with the C# SDK for PayPal Adaptive Payments. Unfortunately the docs aren’t too great and the samples are a little confusing until you get your head around them.

One of the main issues I’ve had is working out how to configure payment request settings i.e. reverseAllparallelPaymentsOnError.

To do this, simple utilise the PayRequest class:

PayRequest requestPay = new PayRequest(envelopeRequest, "PAY", "http://localhost:53034/orders/cancel", "AUD", receiverList, "http://localhost:53034/orders/return");
requestPay.reverseAllParallelPaymentsOnError = true;

Application ID – PayPal Sandbox

Hey everyone,

Just setting up an app that using the .NET Adaptive Payments SDK. Looking through the sandbox I was able to find the api signature, password and username but not the application ID (My Account > Overview > Account Information > API Access).

It turns out that ALL sandbox apps share the same ID:

Application ID: APP-80W284485P519543T

A project with an output type of class library cannot be started directly – MVC Project with Class Library

Hey everyone,

Just another quick post for fixing the following error in a multi-project solution:

A project with an output type of class library cannot be started directly

Simply right click on the project that you want to start and select “Set as StartUp Project”.

Source: http://stackoverflow.com/a/10004706/522859

Route Parameters – AngularJS

Hey everyone,

This is just a quick post on what I did to get my routes working properly with AngularJS. My routes looked like this:

//Configure routes
app.config(function ($routeProvider) {
    $routeProvider
		//...
        .when('/Businesses/Details/:id', {
            templateUrl: '/Businesses/Details'
        })
        //...
	.otherwise({
	    redirectTo: '/'
	});
});

And then to access the ID parameter I used $routeParams:


/* Used to display the lesson planner for customers */
app.controller("CustomerPlannerController", function ($scope, $routeParams /*, ... */) {
     console.log($routeParams);
     console.log($routeParams.id);
}

Using that setup, a route to /Businesses/Details/:id will display the following output in the console:

//Route to: /Businesses/Details/:id
Object {id: "1"} 
1

Note that you can call ID whatever you want, just make sure you change your route to match. Hopefully that’ll be enough to get you going, but if you have any issues check out these links:
http://stackoverflow.com/a/11064503/522859
http://docs.angularjs.org/api/ngRoute.$routeParams

There is already an open DataReader associated with this Command which must be closed first. – ASP.NET MVC

Hey everyone,

I ran into the following error this morning:

There is already an open DataReader associated with this Command which must be closed first.

It turns out there are a few causes for this. My issue was that I was attempting to open a result set while already iterating over another one.


 //Retrieve list of cart products and create list of suborders
 var cartProducts = db.CartProducts.Where(cartProduct => cartProduct.CartId == userOrder.CartId);

//Loop through each cart product
foreach(var cartProduct in cartProducts)
{
     //Retrieve suborder
     SubOrder subOrder = subOrders.Find(x => x.BusinessId == cartProduct.Product.BusinessId);

The solution to this was pretty easy thankfully. Simply add “ToList()” to the end of the initial request:


 //Retrieve list of cart products and create list of suborders
 var cartProducts = db.CartProducts.Where(cartProduct => cartProduct.CartId == userOrder.CartId).ToList();

An alternative solution is to modify your connection string in order to allow multiple result multiple result sets. Simply add the following to provider part:

MultipleActiveResultSets=true

Checkout these StackOverflow posts for more info:
http://stackoverflow.com/a/10498776/522859
http://stackoverflow.com/a/6064422/522859

TimeSelector / TimePicker Directive – AngularJS

Hey everyone,

I’ve been mucking around with directives for that last few days and one of my requirements has been a simple timepicker. Nothing too fancy, but if anyone would like to use it – feel free.

See the following fiddle for the demo: http://jsfiddle.net/LFB3F/2/

Timepicker Directive
Timepicker Directive

The directive is initialised with both the hour and minute defaults being set like this:


Note that hours and minutes should be set in the controller that wraps around the Timepicker:

app.controller("MyCtrl", function MyCtrl($scope) {
    $scope.hours = 11;
    $scope.minutes = 45;       
});

The hours and minutes will then be updated whenever the user changes the value. If you need any other hooks it’s fairly easy to modify and there are a heap of comments.

You may also want to put the HTML in an external template. Just make the following changes to the directive (note templateURL):

app.directive("ngTimeSelector", function () {
    return {
        restrict: 'EA',
        templateUrl: '/Directives/TimeSelector',
        scope: {
            hours: "=",
            minutes: "="
        },
        replace: true,
        link: function (scope, elem, attr) {
...
...

The JSFiddle is probably the easiest way to see how it all works. You can simply copy it from there to your app. Alternatively, I’ve dumped the code below:

Uncondensed HTML (for those who prefer to use a template)

{{displayHours()}}
{{displayMinutes()}}
= 12" class="display"> PM
<div ng-if="hours AM

Timepicker Directive

/* 
    http://www.whatibroke.com/?p=899
*/

var app = angular.module('myApp', []);

app.controller("MyCtrl", function MyCtrl($scope) {
    $scope.hours = 11;
    $scope.minutes = 45;       
});


app.directive("ngTimeSelector", function () {
    return {
        restrict: 'EA',
        template: '
{{displayHours()}}
{{displayMinutes()}}
= 12" class="display"> PM
<div ng-if="hours AM
', scope: { hours: "=", minutes: "=" }, replace: true, link: function (scope, elem, attr) { //Create vars scope.period = "AM"; /* Increases hours by one */ scope.increaseHours = function () { //Check whether hours have reached max if (scope.hours < 23) { scope.hours = ++scope.hours; } else { scope.hours = 0; } } /* Decreases hours by one */ scope.decreaseHours = function () { //Check whether hours have reached min scope.hours = scope.hours = 59) { scope.minutes = 0; } else { scope.minutes++; } } /* Decreases minutes by one */ scope.decreaseMinutes = function () { //Check whether to reset if (scope.minutes 12) { hoursToDisplay = scope.hours - 12; } //Check for 12 AM etc if (hoursToDisplay == 0) { //Set to am and display 12 hoursToDisplay = 12; } else { //Check whether to prepend 0 if (hoursToDisplay <= 9) { hoursToDisplay = "0" + hoursToDisplay; } } return hoursToDisplay; } /* Displays minutes */ scope.displayMinutes = function () { return scope.minutes = 12 ? scope.hours - 12 : scope.hours + 12; } } } });

Styles

body{
	background-color: #F0F0F0;
	font-family: "Lato", sans-serif;
	font-weight: 300;
	color: #363636;
}

.timeSelectorDirective {
    background: none;
    -webkit-user-select: none;      
    -moz-user-select: none;
    -ms-user-select: none;
    -o-user-select: none;
    user-select: none;
}
.timeSelectorDirective .increase, .timeSelectorDirective .decrease{
    text-align: center;
    vertical-align: middle;    
    color: rgb(112, 112, 112);    
    text-shadow: 0px 1px #FFF;
    cursor: pointer;
    -webkit-transition: 500ms ease-out all;
    -moz-transition: 500ms ease-out all;
    -ms-transition: 500ms ease-out all;
    -o-transition: 500ms ease-out all;
    transition: 500ms ease-out all;
    font-size: 100%;
    border: 1px solid #CCC;
    padding: 3px;
    margin: 3px;
    border: 1px solid #EDE;
}

.timeSelectorDirective .increase:hover, .timeSelectorDirective .decrease:hover{
    color: rgba(112, 112, 112, 0.5);   
    border-color: #CCC;
    background-color: #FFF;
}

.timeSelectorDirective .increase:active, .timeSelectorDirective .decrease:active{
    color: rgb(112, 112, 112);
    box-shadow: inset 1px 1px 1px #DDD;
}

.timeSelectorDirective .section{
    display: inline-block;
}

.timeSelectorDirective .display{
    background-color: rgb(247, 247, 247);
    color: #555555;
    padding: 5px;
    margin: 0px 3px;
    min-width: 30px;
    text-align: center;
    border: 1px solid #DDD;
    box-shadow: 1px 1px 1px #FFFFFF;
}

Sample Usage

www.whatibroke.com

Hours: {{hours}}   Minutes: {{minutes}}

Misc Includes
AngularJS: http://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.js
FontAwesome: http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css
Font: http://fonts.googleapis.com/css?family=Lato:300,300italic,400,700,700italic|Rokkitt:400,700.css

Passing Parameters from a Directive to a Function – AngularJS

Hey everyone,

This is just a quick post to help out anyone who runs into the same problems with directives that I did today. I was able to call the controllers function from the directive, however none of the parameters were being passed.

The issue ended up being that the parameters need to be named. For instance:

 
app.directive('ngPlanner', function () {
    return {
        restrict: 'EA',
        templateUrl: '/Businesses/PlannerDirective',
        scope: {
            lessons: "=",
            business: "=",
            lessonClicked: "&",
            addLesson: "&"
        },
        replace: true,
        link: function (scope, elem, attr) {
            var selectedIndex = null;

            console.log(scope);
            console.log(scope.lessons);
            scope.test = function (tester) {
                selectedIndex = tester;
                console.log("Directive: " + selectedIndex);
                scope.lessonClicked({ lesson: selectedIndex });
            }
        }
    }
});

/* Used for handling business details, planner, etc */
app.controller("BusinessDetailsController", function ($scope) {

    //Fired when the new lesson button is clicked in the planner directive
    $scope.newLesson = function (date) {
        console.log("New Lesson Clicked: " + date);
    }

    //Fired when a lesson is clicked on
    $scope.editLesson = function (lesson) {
        console.log("Lesson Clicked: " + lesson);
    }
});

Note particularly the scope.lessonClicked line. Instead of passing parameters normally, they should be named (scope.lessonClicked({lesson: selectedIndex}).

The naming should match that used in the HTML where your directive is added:
<ng-planner lessons=”plannerLessons” lesson-clicked=”editLesson(lesson)” add-lesson=”newLesson()” business=”true”></ng-planner>

A huge thanks to Jay B for posting the solution on the AngularJS groups page: https://groups.google.com/forum/#!topic/angular/3CHdR_THaNw

He’s also added the following JSFiddle: http://jsfiddle.net/simpulton/VJ94U/

And although pretty well hidden, it is actually mentioned in the documentation: http://docs.angularjs.org/guide/directive

Select List (ng-select) – AngularJS

Hey everyone,

Just a quick post on how to do up a select list in AngularJS. This one took a bit of time to work out, particularly the display/value pairing.

HTML:

Status:

JavaScript:

var myApp = angular.module('myApp', []);

function MyCtrl($scope) {
    $scope.status_options = [
            { display: 'Enabled', value: 'enabled' },
            { display: 'Disabled', value: 'disabled' },
            { display: 'Deleted', value: 'deleted' }
        ];
    
    $scope.lesson = {
        BusinessId: 0,
        Description: null,
        Duration: 0,
        Price: 0,
        ProductId: 0,
        Quantity: 0,
        Start: "/Date(-62135596800000)/",
        Status: 'enabled', //Change to null in order to remove default
        Title: null,
        Type: null
    };
}

If you’re just following along, I’ve added a quick JSFiddle: http://jsfiddle.net/rtR6e/5/

You’ll notice that in the markup, the value is actually an index. This is pretty misleading, but Angular will actually assign the appropriate value to the model (“enabled”, “disabled”, etc).

Another thing that you can do fairly easily, is to remove the default value. Simply make the status null. You can test both these by outputting the JSON or using http://jsfiddle.net/rtR6e/5/.

Check out the following StackOverflow post for more info: http://stackoverflow.com/a/13808743/522859
Or the documentation: http://docs.angularjs.org/api/ng.directive:select

Suddenly Getting The EntityFramework package is not installed on project ”. – ASP.NET MVC

Hey everyone,

I am working on a small project done in ASP.NET MVC4 and started getting the following error:

The EntityFramework package is not installed on project ”.

Get-Package : Cannot validate argument on parameter ‘ProjectName’. The argument is null or empty. Supply an argument that is not null or empty and then try the command again.
At C:SitesLearnerLessonspackagesEntityFramework.5.0.0toolsEntityFramework.psm1:611 char:40
+ $package = Get-Package -ProjectName <<<< $project.FullName | ?{ $_.Id -eq 'EntityFramework' }
+ CategoryInfo : InvalidData: (:) [Get-Package], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,NuGet.PowerShell.Commands.GetPackageCommand

The confusing thing was that I’d used it no more than an hour ago. The following StackOverflow post reveals the issue (and the fact that I should’ve read the error more carefully):

http://stackoverflow.com/a/14708897/522859

All I needed to do was select the correct project from the “Default Project” dropdown in the Package Manager Console:

The EntityFramework package is not installed on project ''
The EntityFramework package is not installed on project ”