ExLibrisGroup / exl-touchnet-connector

Connector between Ex Libris Alma and Primo and the Touchnet payment system
MIT License
1 stars 1 forks source link

Development request: support multi-institution Alma Touchnet integration #12

Closed HSteeleLTS closed 2 years ago

HSteeleLTS commented 3 years ago

We're excited about using the Alma Touchnet connector to automate Touchnet payments into Alma, however we have found that in its current form we can't implement. The reason is we are a multi-branch institution with different libraries each with different funds into which fines money is paid. Right now patrons pay fines in Touchnet by navigating to a separate Touchnet payment page, corresponding to a different library and account, for each library.

Currently, the Alma Touchnet connector can only send payments to one Touchnet site. Then when the payment request comes back, it pays against that patrons account, in Alma, paying off the oldest fine first, then the next oldest, etc. regardless of what library they belong to.

What I'm suggesting, although I'm very open to alternate suggestions, is that the connector/Primo provide a drop down menu in Primo to allow the user to choose which libraries fines they'd like to pay. Then it sends along with the request data that is sent to Touchnet that also comes back to the connector, the fine_ids of the charges that correspond to that library. perhaps it could also prefill the amount on the Touchnet payment form. Then only this library's fines would be paid and the money would go into the correct account. Obviously there might need to be some configuration allowed, or set up in the connector/Primo if several libraries use the same payment account.

Let me know how feasible this might be in terms of development

jweisman commented 3 years ago

Hi @HSteeleLTS - thanks for the suggestion. To make sure I understand the use case here- each library has its own Touchnet set up- (Site ID and Site URL), on which is configured the appropriate account information. Once the fines are paid for a particular library, only those fines should be credited in Alma.

In theory, that could be solved by having the connector accept a library parameter. It would then query only fines related to that library, and only pay those off after the payment process is complete.

Does that make sense to you?

HSteeleLTS commented 3 years ago

Yes! Yes thank you for parsing the use case this way. That's what I'm thinking. And ideally a drop down or the like in Primo whose choices of library were limited to those at which the user owed fines.

But honestly we'd be happy with any version that supported multi-library functionality to start with. For instance if we just set up multiple fines payment links in Primo on our end, and maybe some display logic if that were possible in Primo back office /VE configuration that we did, and the connector routed them to link them to the right uPay site, that would be great too

jweisman commented 3 years ago

Hi @HSteeleLTS - We added some handling for library in the connector code. It relies on an environment variable named ALMA_LIBRARY_CODE. So you can set up an instance of the connector with the relevant UPay parameters and the library code for your desired library.

It would be great if you could try it out and let us know if you have any feedback. Thanks.

HSteeleLTS commented 3 years ago

Thank you for working on this update! I am going to test this as soon as I can get a test instance of Touchnet at our institution, working with our Touchnet administrator.

One question: how do you suggest we implement this in Primo My Account, with multiple Touchnet uPay sites? I was thinking we could have a drop down with the libraries in the patrons' fines. Is this also something that you all could develop, as a snippet that could be put into Primo? Or are you thinking of this functionality working differently in Primo? Any suggestions welcome!

HSteeleLTS commented 3 years ago

Thinking about this in a more minimal way in conjunction with information Ross gave me on the Support Portal ticket, we can just have links for each libraries' separate fines portal. Ideally this would be limited to those libraries whose charges are on the patron record, but this is something that would have to be figured out with some custom configuration.

Without looking in detail into the new application here, how does this connector know what library is being sent from Primo? I assume it's receiving that request. Also maybe this is custom development that I would need to do, but ideally if it's getting a link from X library, then the connector would query the user API and find out the total value of fines owed to that library by that patron. And then send that amount to Touchnet as something that would hopefully appear in the box.

But this may be 2.0 As a minimal working version, if the library to which the patron wants to pay fines is represented in the request, and the connector only pays off fines in Alma at that library, this should work for us.

Thanks for your work on this. I will work more with this when we have a test environment through Touchnet

jweisman commented 3 years ago

Hi @HSteeleLTS - since the uPay details are stored in the connector's environment, the library code is stored there too (as ALMA_LIBRARY_CODE). The connector queries the fines for that library only, and then applies the payment to those fines once the payment is completed in Touchnet. So you would probably want to set up multiple instances of the connector for each library with its code and Touchnet uPay details.

As for how this could be displayed in Primo, that would be out of scope for the connector. I can envision perhaps the Pay Fines link in Primo going to a page on your library portal which contains links to the relevant connector URL. It would need to pass the JWT token as well, so I suppose the page would need some JavaScript to get the token from the querystring and append it to the links.

Of course, there are other options as well, such as building a JS popup in Primo using the customization features.

Let us know how your testing goes.

HSteeleLTS commented 3 years ago

This is great. Thanks. I agree that having a landing page, which in fact is what we have now, is the way to go. I've looked through the code and saw how in alma.js it limits the fines to pay by library.

I guess my remaining question is what would our landing page need to have to integrate with the connector. Here is our landing page: https://www.library.tufts.edu/fees/ It contains links to each library's separate Touchnet uPay site. If the link is coming from Primo My Account, how could we this page receive that request and add to it to pass to the connector what library was chosen. Then like you say we'd have a different connector for each library, and it would pass that library name to the connector also so it was only querying that library's fees

HSteeleLTS commented 3 years ago

I'm assuming this page has to be reconstructed so it would be some kind of listener, and could receive requests from Primo My Account, and pass them./integrate with the connector. I realize this is something we would need to develop, but I'm just wondering what the best strategy is here

jweisman commented 3 years ago

Hi @HSteeleLTS - one possible implementation is to simply change your existing fines page to point to the Touchnet connector for each library. So the steps would be as follows:

  1. Configure Primo VE to point the pay fines link to the landing page, as described here
  2. Set up the various connectors with the proper uPay and library environment parameters
  3. Change the fees landing page to point to the Touchnet connector links, along with some JavaScript code which adds the identifying token which Primo passed in. Something like this:


Hope this makes sense.
HSteeleLTS commented 2 years ago

Thank you again for this further development on the connector. We are truly excited about being able to use it.

I am working on a PoC for this, and am running into a snag. I tried both setting this up on a local server, and trying the heroku deployment method which is better documented. In either case I can get to a state where I don't have errors, but nothing happens, and I can't confirm the app is actually doing anything.

For the purpose of testing, I've not included that landing page so it was going directly from Primo VE to the website. I get this URL: https://exl-touchnet-connector-tufts-2.herokuapp.com/?jwt=eyJraWQiOiJwcmltYVByaXZhdGVLZXktMDFUVU5fSU5TVCIsImFsZyI6IkVTMjU2In0.eyJpc3MiOiJQcmltYSIsImp0aSI6IjVCNjgwQ0ZGQkRERjEzNkY4MTgwQkI4QzM0M0U4MzNFLmFwZDAxLm5hMDEucHJvZC5hbG1hLmRjMDQuaG9zdGVkLmV4bGlicmlzZ3JvdXAuY29tOjE4MDEiLCJleHAiOjE2Mzk1MTYzOTgsImlhdCI6MTYzOTQyOTk5OCwidXNlck5hbWUiOiI0OUUzQUIzRjA5MjBFNkIyQTY1MDZERUU0MDNCMEZGMyIsImRpc3BsYXlOYW1lIjoiU3RlZWxlLCBIZW5yeSIsInVzZXIiOiI0OTYzMDg2MzAwMDM4NTEiLCJ1c2VyR3JvdXAiOiJTdGFmZiIsImluc3RpdHV0aW9uIjoiMDFUVU5fSU5TVCIsInVzZXJJcCI6IjEzMC42NC40MS4xOTkiLCJhdXRoZW50aWNhdGlvblByb2ZpbGUiOiJUVUZUUyBTQU1MIiwiYXV0aGVudGljYXRpb25TeXN0ZW0iOiJTQU1MIiwibGFuZ3VhZ2UiOiJlbiIsInNhbWxTZXNzaW9uSW5kZXgiOiJfMTY3ZTZkZGRjY2M0MzcyZTM5YWJiN2U2NDk2ZjhhZWUiLCJzYW1sTmFtZUlkIjoiQUFkelpXTnlaWFF4YzkxM1JKL0ptd0MxMDdNaDVQRlZhbGhHOWhUbVdOUWtZeWZ0ekxoQmZTYnlqYVFHNXdReUlueFlzQld2ME5jRFJQbUlqamovYUdoMk5MN040anVjZHllUGI4SmxVRUVuNzlBcThQQXJaQkhpOUJHaVdyQ25JSjlORGUyR09FYnhBNWhvRS8rVWNDYzY0K1R0elVIWEJzRzY3Z240N2c9PSIsIm9uQ2FtcHVzIjoiZmFsc2UiLCJzaWduZWRJbiI6InRydWUiLCJ2aWV3SWQiOiIwMVRVTl9JTlNUOjAxVFVOIn0.6VkzCmVzamQ7TKOL2PxQ40p-qmJvXG5kOrGNgYE5zGi11GyimhDDUvu2CnYtQXi_534OLJqbLr6HQnMuMf7syg

Feel free to click on this, because although this is my account, it's test data. In Heroku logs, I see a 200 response for this. but there's no redirect to the Touchnet test instance. Note that the Primo VE documentation on your README page says I should append "touchnet?" to the end of the app URL. When I do this, with the jwt= token after that, I get a 400 and the following error: "Unexpected token < in JSON at position 0"

With heroku, e.g. I have all the 5 environment variables configured.

What do you think the issue is? I'm happy to meet with you on Zoom etc. if you think that would help

jweisman commented 2 years ago

Hi @HSteeleLTS . I believe this is because the Alma REST API is throwing an error which is returned in XML instead of JSON. This happens usually when the API key is not configured correctly.

To test this theory, can you try to go in a browser to https://api-na.hosted.exlibrisgroup.com/almaws/v1/users/49E3AB3F0920E6B2A6506DEE403B0FF3?apikey=YOUR_API_KEY with the key configured in the Heroku environment? You can then see the error message more clearly.

HSteeleLTS commented 2 years ago

thanks. This definitely brought us to the next step. The problem now is we're trying to test in Primo Classic/back office and we don't seem to be able to define a link as defined this README that will generate a jwt.

This is the link I provided, based on our Heroku app: https://git.heroku.com/exl-touchnet-connector-tufts-2/touchnet?institution=01TUN.

We don't know anything about a PDS handle. We though we didn't need this generally because we're on SAML. Do we need to do something with this? What are we doing wrong?

jweisman commented 2 years ago

Are you using Primo or Primo VE?

HSteeleLTS commented 2 years ago

Primo Classic for now. We will be switching to Primo VE soon, but don't have a sandbox environment for this yet

jweisman commented 2 years ago

Hi @HSteeleLTS - looking at the instructions for Primo it seems the link should be something like: https://exl-touchnet-connector-tufts-2.herokuapps.com/touchnet?institution=01TUN&pds_handle={{pds_handle}}

HSteeleLTS commented 2 years ago

We tried entering the link above in the Primo back office payment link settings. When I go to the app page, Primo generates an auth pds_handle for the user I log in as, but I get the message "Cannot retrieve user details information." and in the error messages of the page "400 - bad request"

I looked more at the documentation for setting this up in classic primo. The README links to this page: https://knowledge.exlibrisgroup.com/Alma/Product_Documentation/010Alma_Online_Help_(English)/060Alma-Primo_Integration/040Configuring_the_Primo_Front_End_for_an_Alma_Data_Source/070My_Account#Configuring_the_Pay_Fine_Link which says "To allow users to pay fines online using My Account, you must configure the link to the WPM Education E-Payment System" THis in addition to the message on the page linked from here https://knowledge.exlibrisgroup.com/Alma/Product_Documentation/010Alma_Online_Help_(English)/090Integrations_with_External_Systems/040Fulfillment/090WPM_Education_E-Payment_System

that says "https://knowledge.exlibrisgroup.com/Alma/Product_Documentation/010Alma_Online_Help_(English)/090Integrations_with_External_Systems/040Fulfillment/090WPM_Education_E-Payment_SystemThe WPM Education online payment system is available to UK customers only."

indicates to me that we may not be able to test the connector with classic Primo (new UI). Is this assumption correct?

Another question. We're moving to Primo VE this Wednesday in prod. Is there any way to easily set this up on the sandbox and not have to wait for the sandbox refresh in Feburary?

Note that I did get this working in Primo VE/Discovery. So I can verify that connector works! At least for Primo VE. The connector connected from My Account in Primo VE through the connector to our Touchnet test instance, and the amount reflected in this request that Touchnet received was only the amount due at one particular library. So this is good. More testing will have to wait until I can really do this in the Alma/Primo sandbox.

I do have one other question about all this. The amount due at a given library is charges minus credits. Let's say at the library I'm paying at I have $60.00 in 2 $30.00 charges and $20.00 in credits. the amount that the connector sends to Touchnet should be $40.00. So then I'm presuming what will happen when the user pays is one $30.00 charge will be paid off completely, and the other will have a remaining balance of $20.00. Is this right? Then the balance due at that library will be $0.00, with equal credits and charges. I'm just checking my assumptions. We probably want to go through and clear any stray credits before we enable this

jweisman commented 2 years ago

Hi @HSteeleLTS.

We tried entering the link above in the Primo back office payment link settings. When I go to the app page, Primo generates an auth pds_handle for the user I log in as, but I get the message "Cannot retrieve user details information." and in the error messages of the page "400 - bad request"

That's a good sign- it means we got to the part of the code which works with the PDS handle. Can you check the log output of the connector? Do you have access to it?

You can ignore the WPM documentation. We're using the Touchnet connector because only WPM is supported natively in Alma/Primo.

Another question. We're moving to Primo VE this Wednesday in prod. Is there any way to easily set this up on the sandbox and not have to wait for the sandbox refresh in Feburary?

I'm not sure about your question here. Are you asking because Primo VE is not enabled in your sandbox? If so, I don't know the answer to that- sorry.

I do have one other question about all this. The amount due at a given library is charges minus credits. Let's say at the library I'm paying at I have $60.00 in 2 $30.00 charges and $20.00 in credits. the amount that the connector sends to Touchnet should be $40.00. So then I'm presuming what will happen when the user pays is one $30.00 charge will be paid off completely, and the other will have a remaining balance of $20.00. Is this right? Then the balance due at that library will be $0.00, with equal credits and charges. I'm just checking my assumptions. We probably want to go through and clear any stray credits before we enable this

I believe your assumptions are correct.

HSteeleLTS commented 2 years ago

I don't have the log output for the connector. I'm running this on heroku now, although I'm still looking there to see if there's something buried I haven't found yet. I see the application itself doesn't seem to explicitly create logs

HSteeleLTS commented 2 years ago

Actually I do see some kind of logs in the heroku CLI. Does this help you troubleshoot:

2022-01-14T09:39:47.109446+00:00 app[web.1]: Error in retrieving user information: Invalid URL: undefined 2022-01-14T09:39:47.113843+00:00 heroku[router]: at=info method=GET path="/touchnet?institution=01TUN&pds_handle=oauth_email_ed226f46ac174a39a1af3c4daaadd0cd" host=exl-touchnet-connector-tufts-2.herokuapp.com request_id=432c29c9-3894-42fb-a8bb-0de7a73bdfd3 fwd="130.64.41.214" dyno=web.1 connect=0ms service=9ms status=400 bytes=250 protocol=https

HSteeleLTS commented 2 years ago

When I try to go to the link called in app/index.js for Primo Classic directly, which is https://tufts-psb.alma.exlibrisgroup.com/primo_library/libweb/webservices/rest/PDSUserInfo?institute=01TUN&pds_handle=oauth_email_ed226f46ac174a39a1af3c4daaadd0cd, I get a 400 error. So this indicates that this is not working.

But if you see the lihk below, it seems like there may be some more set up for us to use PDS handles?

https://knowledge.exlibrisgroup.com/Primo/Knowledge_Articles/How_to_allow_production_Alma_to_return_responses_to_a_sandbox_Primo

HSteeleLTS commented 2 years ago

And looking at this page if we don't have PDS authentication enabled I'm not sure how this would work:

https://knowledge.exlibrisgroup.com/Primo/Product_Documentation/Primo/Back_Office_Guide/040Primo_User_Authentication/090Using_PDS_for_User_Authentication

HSteeleLTS commented 2 years ago

I actually tried this one which looks more correct:

https://tufts-primosb.hosted.exlibrisgroup.com/primo_library/libweb/webservices/rest/PDSUserInfo?institute=01TUN&pds_handle=oauth_email_ed226f46ac174a39a1af3c4daaadd0cd

HSteeleLTS commented 2 years ago

good news! I was able to sidestep the whole PDS question because my coworker was able to enable Primo VE for the sandbox. So I could use that method. I was able to go from the payment link in My Account in the Primo VE sandbox. It was processed by the connector and sent to the Touchnet test site. I made a payment here using a test credit card number, and the charges cleared in the Alma sandbox.

I will probably have more questions as I continue my testing, but my only now is the payment type these payments come through as. They are coming through as "jumbocash" I think this is because the code sends the payment as type "online" we would like to send the payments as the type that maps to "Credit card" I can alter our local code, but I'm wondering if you know what payment code corresponds to "Credit Card"

jweisman commented 2 years ago

Hi @HSteeleLTS - glad to hear you were able to get it working with Primo VE.

Regarding the question of payment method, the ONLINE method is hard coded in the connector. The options available are documented as follows:

The Payment method. Relevant and mandatory if op=pay. Options are CREDIT_CARD, ONLINE, or CASH

HSteeleLTS commented 2 years ago

Hey there I wanted to give you an opportunity to look a slight modification I've made to the connector that allows multiple branches to be handled by a single instance of the application. I'm attaching a diff html file from WinMerge, because I think it's easier to look at, but you'll see there are only slight modifications to one file in the applications, app/index.js.

What this version does is it receives a library code from the referring URL and uses this to assign the library at which to pay fines. This is a regular URL parameter not encoded in the JWT. Although I could have passed the upay_site_id as another URL parameter, and this may be the better way to go, what I've done instead is turn the ALMA_LIBRARYC_CODE environment variable into a dict like string that can be parsed for the upay site ID as a JSON object with key value pairs.

Note also our landing page that routes traffic to different libraries (also attached ) uses your JS snippet to grab the JWT, and also assigns this library code.

I wanted to provide this slight alteration to the code back to you in case you wanted to use this or some similar strategy to make the application easier to manage for multiple institutions.
for ExL.zip

jweisman commented 2 years ago

Hi @HSteeleLTS - thanks for sharing the code. I'm glad you were able to find a solution that worked for you! I'll close this issue for now. Let us know if anything else comes up.

puck78 commented 2 years ago

I do want to add one more comment/question to this ticket. I had set up a proof of concept of this on heroku and all worked well. But when I tried to set this up on a local server the application worked most of the way through but couldn't actually connect to Touchnet. It got stuck on this section of code /app/index.js 90-98

I think what's happening according to the link below is our staging server doesn't have an HTTPS endpoint yet from which to refer traffic to the Touchnet test server. I suspect that's why Touchnet is rejecting the traffic. I am working on getting HTTPS endpoints on this, but I wonder if you had any other insights about why this might be the case.

The error I get is from these two lines of code:

console.error("Error in setting up payment:", e.message)
throw new Error('Cannot prepare payment information.');

goprintsupport.com/TouchNet_Credit_Card_Configuration.pdf let ticket = await touchnet.generateTicket(user_id, { amount: total_sum, success: returnUrl + '/success', error: returnUrl + '/error', cancel: referrer, referrer, post_message, institution });

jweisman commented 2 years ago

Hi @puck78 - I believe Touchnet blocks traffic to their API and only opens it up for certain IPs. I would check with your Touchnet implementation consultant to see what's required to test this locally.

HSteeleLTS commented 2 years ago

Thanks , Josh. I did this on Heroku without instance. Of course they may have whitelisted that by default. Of course I didn’t give them this IP. Do you think it’s different ? Either way I’ll reach out

puck78 commented 2 years ago

Touchnet confirmed that they don't blacklist or whitelist any incoming trafffic.

I think this is the source of the issue, described on this Stack Overflow page. It seems like it has to do with http non secure requests in Node JS

https://stackoverflow.com/questions/33350604/what-could-cause-connect-etimedout-error-when-the-url-is-working-in-browser

the issue is even though we will provide an HTTPs endpoint for this, the way our server architecture works is the back end is HTTP, for instance at our current address of libapps-stage-01.uit.tufts.edu:3002 This is the address now of the connector app. This then goes through a load balancer and the frontend HTTPS endpoint will point to it. But as far as Node JS is concerned its address will still be HTTP. Unless there's someway I can change this in the code?

At the link above they talk about using a proxy for such situations. Do you have any idea how I could do this in this case?

jweisman commented 2 years ago

Hi @puck78 - this StackOverflow post refers to a situation where your server doesn't have access to the Internet or is behind an institutional proxy. Can you try to reach the Touchnet webservice URL from the local server:

curl https://secure.touchnet.com:8702/tlinkauth/services/TPGSecureLink

See if you get any response .

puck78 commented 2 years ago

Thanks for your help with this. That indeed was the issue. On our local server we had to configure the firewall rule to allow outgoing traffic to port :8702 Once I did that the payments went through correctly.

There's one last piece of this though that doesn't seem to work, at least in the way I am using it. I can open another issue here for it if you want.

I'm not getting any luck with the success page once I successfully make a payment. When it uses the referrer as the return URL it says it can't find that page: "?touchnet/null" According to your instructions on the README I can specify a return URL. I have done this in the Javascript if you look at the fines landing page, but when the payment comes back from Touchnet I get the response "Cannot POST /success" It goes to the URL http://libapps-stage-01.uit.tufts.edu:3002/success?institution=01TUN_INST&UPAY_SITE_ID=43

Here is the URL of the fines page, with a jwt: https://www.library.tufts.edu/hsteele/alma_touchnet_integration/index.html?&jwt=eyJraWQiOiJwcmltYVByaXZhdGVLZXktMDFUVU5fSU5TVCIsImFsZyI6IkVTMjU2In0.eyJpc3MiOiJQcmltYSIsImp0aSI6IjRBRjcwRUFBOTU5QUI1QTkwMzg1MkY3NzU0OTc4NjY5LmFwcDAxLm5hMDEucHNiLmFsbWEuZGMwMS5ob3N0ZWQuZXhsaWJyaXNncm91cC5jb206MTgwMSIsImV4cCI6MTY0NDUyNTQ4OSwiaWF0IjoxNjQ0NDM5MDg5LCJ1c2VyTmFtZSI6IjQ5RTNBQjNGMDkyMEU2QjJBNjUwNkRFRTQwM0IwRkYzIiwiZGlzcGxheU5hbWUiOiJTdGVlbGUsIEhlbnJ5IiwidXNlciI6IjQ5NjMwODYzMDAwMzg1MSIsInVzZXJHcm91cCI6IlN0YWZmIiwiaW5zdGl0dXRpb24iOiIwMVRVTl9JTlNUIiwidXNlcklwIjoiMTMwLjY0LjQxLjE1OCIsImF1dGhlbnRpY2F0aW9uUHJvZmlsZSI6IkVNQUlMIiwiYXV0aGVudGljYXRpb25TeXN0ZW0iOiJBbG1hIiwibGFuZ3VhZ2UiOiJlbiIsInNhbWxTZXNzaW9uSW5kZXgiOiIiLCJzYW1sTmFtZUlkIjoiIiwib25DYW1wdXMiOiJmYWxzZSIsInNpZ25lZEluIjoidHJ1ZSIsInZpZXdJZCI6IjAxVFVOX0lOU1Q6MDFUVU4ifQ.P4afHZtlZ7Zo3bDtIuJ0TH5oKtEnIuPoxzZ6JHUw_Ewb-0x3X5NyfWwrpUF5ke4bL0NOeotEu9CxXpXAnLdnOQ

puck78 commented 2 years ago

Btw, I hard coded the returnUrl and refferer to https://www.library.tufts.edu and now for some reason it brings the user back to Primo. But still no success or cancel page. Until we work through this could we move this ticket back to open?

And one other question. How do I keep this application running all the time? I tried running it with "npm start &" and nohup npm start &, but either when I log off the server I can't reach the application

jweisman commented 2 years ago

Hi @puck78 - glad to hear you got it running on your local server. I opened #21 for the question on the return URL.