npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@nait-aits/moneris

v0.0.2

Published

```console // with npm npm install @nait-aits/moneris ```

Downloads

3

Readme

Installation

// with npm
npm install @nait-aits/moneris

What is this?

This package contains a control(MonerisChecoutPanel) that will help using moneris for payment. You can include this component on your page and it will make it easier to integrate into your application.

There are a few things that make using moneris a bit difficult when using react/typescript, so hopefully this simplifies things a bit.

Usage

<MonerisChecoutPanel<{data: number}>
  createTransactionData={{
    someData: {order: 123},
  }}
  createTransactionUrl={'https://urlToCreateTransaction'}
  processPaymentUrl={'https://urlToProcessAfterPayment'}
  cancelTransactionUrl={'https://urlForCancelledTransaction'}
  getAuthToken={promiseToGetToken}
  onComplete={paymentData => {
    //Handle what the app should do when everything is done
    //payment data is the type of the generic for the panel
    console.log('onComplete called', paymentData);
  }}
  onCancel={() => {
    //Handle what the app should do when user cancels
    console.log('onCancel called');
    
  }}
  onError={error => {
    //Handle what the app should do when moneris errors
    console.log('onError called');
  }}
  activated={trueIfYouWantToActivate}
/>

Order things happen

  1. User Clicks Pay Button
    • set activated parameter to true
  2. createTransactionUrl is called, with the createTransactionData data posted
    • Server creates moneris ticket and returns moneris ticket to the client
  3. Client pays via moneris interface
  4. processPaymentUrl is called with the ticket as a parameter
    • server verifies ticket is paid and then processes
  5. onComplete is called

Server side notes

  • There is code at the end for the MonerisRepository

Sample C# code

[Authorize]
[HttpPost("CreateOrderTransaction")]
public async Task<object> CreateOrderTransaction([FromForm] List<string> slugs)
{
   ...

    var totals = GetPaymentValues(slugs);

    var transactionId = Guid.NewGuid();

    //create moneris ticket for order (Due to the Kount verification, orderID cannot exceed 32 digits so we need to remove the dashes from the guid)
    var ticket = await _monerisRepo.CreateOrder(totals.Total, transactionId.ToString().Replace("-",""), cartItems);

    ...

    //create some record somewhere to make a note of this transaction that is pending

    //You MUST return an obejct with the monerisTicket property
    return new
    {
        monerisTicket = ticket
    };
}

[Authorize]
[HttpPost("CancelOrderTransaction")]
public async Task<object> CancelOrderTransaction([FromForm] string monerisTicket)
{
    ... 

    //do any cleanup you need to do
    ...

    return new
    {
        ok = true
    };
}

[Authorize]
[HttpPost("ProcessPayment")]
public async Task<object> ProcessPayment([FromForm] string monerisTicket)
{
    var user = CurrentUser;

    //load the transaction

    //get the recept from moneris
    var receiptString = await _monerisRepo.GetPaymentReceipt(monerisTicket);
    transaction.ReceiptJsonData = receiptString;

    //Get the receipt
    var receipt = _monerisRepo.GetReceiptResponse(receiptString);

    if (receipt.success != "true" || receipt.receipt.result != "a")
    {
        if ( receipt.success != "true")
        {
           //The payment was NOT successful
        }

        if( receipt.receipt.result == "d")
        {
            //credit card was declined
        }
    }
    
    //make sure to validate that it is correct amount was paid vs what you were expecting
    //receipt.request.cc_total is the total from the payment

    //payment completed, so do what you need to do now

    //return the obejct that matches the generic type of the control.
    return new
    {
        orderId = newOrder.Id,
        transactionId = transaction.Id,
        subTotal = transaction.Subtotal,
        taxes = transaction.Taxes,
        total = transaction.Total,
        monerisTicket = monerisTicket
    };
}

Pages/notes

Server Side Code

You must use .NET Core as it requires IHttpClientFactory (this is injected in Startup.cs)

  • services.AddHttpClient();

Moneris Documentation

https://developer.moneris.com:3000/livedemo/checkout/overview/guide/dotnet

Moneris Test Card Numbers

https://developer.moneris.com/More/Testing/Testing%20a%20Solution

Moneris development merchant setup

Login info is also displayed on this page

https://esqa.moneris.com/mpg/

public/index.html

You need to make sure that you include the link to the Moneris library.

<!DOCTYPE html>
<html lang="en">
  <head>
    ...
    <script src="https://gatewayt.moneris.com/chkt/js/chkt_v1.00.js"></script>
    ...
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>

C# MonerisRepository Library


using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json;
using System.Threading.Tasks;

namespace YourNameSpace.Repositories.Moneris
{
    public class MonerisRepository
    {
        private IHttpClientFactory _httpClientFactory;
        private string _baseUrl;
        private string _storeId;
        private string _token;
        private string _checkoutId;

        public MonerisRepository(string baseUrl, string storeId, string token, string checkoutId, IHttpClientFactory httpClientFactory)
        {
            _httpClientFactory = httpClientFactory;
            _baseUrl = baseUrl;

            _storeId = storeId;
            _token = token;
            _checkoutId = checkoutId;
        }

        public async Task<string> CreateOrder(decimal amountDue, string orderId, List<MonerisPreloadRequest.CartItem> cartItems = null)
        {
            MonerisPreloadRequest orderData = new MonerisPreloadRequest()
            {
                store_id = _storeId,
                api_token = _token,
                checkout_id = _checkoutId,
                txn_total = String.Format("{0:0.00}", amountDue),
                environment = "qa",
                action = "preload",
                order_no = orderId
            };

            if (cartItems != null && cartItems.Count > 0)
            {
                orderData.cart.items = cartItems;
            }

            var httpClient = _httpClientFactory.CreateClient();

            HttpResponseMessage res = await httpClient.PostAsJsonAsync($"{_baseUrl}/chkt/request/request.php", orderData);

            if (res.IsSuccessStatusCode && res.StatusCode != System.Net.HttpStatusCode.NoContent)
            {
                var response = await res.Content.ReadFromJsonAsync<MonerisPreloadResponse>();

                if (response.response.success == "true")
                {
                    return response.response.ticket;
                }

                throw new Exception(response.response.error.ToString());
            }
            else
            {
                throw new HttpRequestException("Error Creating Ticket from Moneris", inner: null, statusCode: res.StatusCode);
            }
        }

        //we need this as a string as if the object returned isnt as expected we still need to save
        //it to our database or something
        public async Task<string> GetPaymentReceipt(string monerisTicket)
        {
            MonerisReceiptRequest requestData = new MonerisReceiptRequest()
            {
                store_id = _storeId,
                api_token = _token,
                checkout_id = _checkoutId,
                environment = "qa",
                action = "receipt",
                ticket = monerisTicket
            };

            var httpClient = _httpClientFactory.CreateClient();

            HttpResponseMessage res = await httpClient.PostAsJsonAsync($"{_baseUrl}/chkt/request/request.php", requestData);

            if (res.IsSuccessStatusCode && res.StatusCode != System.Net.HttpStatusCode.NoContent)
            {
                var resultText = await res.Content.ReadAsStringAsync();

                return resultText;
            }
            else
            {
                throw new HttpRequestException("Error Retrieving Receipt Request from Moneris", inner: null, statusCode: res.StatusCode);
            }
        }

        public ReceiptResponseItem GetReceiptResponse(string responseContent)
        {
            try
            {
                var response = JsonSerializer.Deserialize<MonerisReceiptResponse>(responseContent);

                if (responseContent == null)
                {
                    throw new Exception("Unable to parse MonerisReceiptResponse object from stream");
                }

                return response.response;

            }
            catch (Exception ex)
            {
                throw new Exception("Unable to parse response JSON");
            }
        }
    }

    public class MonerisReceiptRequest
    {
        public string store_id { get; set; }
        public string api_token { get; set; }
        public string checkout_id { get; set; }
        public string environment { get; set; }
        public string action { get; set; }
        public string ticket { get; set; }
    }

    public class MonerisPreloadRequest
    {
        public string store_id { get; set; }
        public string api_token { get; set; }
        public string checkout_id { get; set; }
        public string txn_total { get; set; }
        public string environment { get; set; }
        public string action { get; set; }
        public string order_no { get; set; }
        public Cart cart { get; set; } = new Cart();

        public class Cart
        {
            public List<CartItem> items { get; set; } = new List<CartItem>();
        }

        public class CartItem
        {
            public string url { get; set; }
            public string description { get; set; }
            public string product_code { get; set; }
            public decimal unit_cost { get; set; }
            public int quantity { get; set; }
        }
    }

    public class PreloadResponseItem
    {
        public string success { get; set; }
        public string ticket { get; set; }
        public object error { get; set; }
    }

    public class MonerisPreloadResponse
    {
        public PreloadResponseItem response { get; set; }
    }
}