Commit 6ae71ff6 by Tuukka Kivilahti

Merge branch 'checkoutRefactor' into 'master'

Checkout.fi payment refactor

Refactor Checkout.fi api requests to allow different queries to checkout api.
This is done to allow creation of bill payment status requests. Api calls exists and all this needs is some ui magick.

also: can has tests \o/

See merge request !256
2 parents 1f8a16f6 2ca46422
...@@ -37,8 +37,7 @@ public class CheckoutBank { ...@@ -37,8 +37,7 @@ public class CheckoutBank {
private static final Logger logger = LoggerFactory.getLogger(CheckoutBank.class); private static final Logger logger = LoggerFactory.getLogger(CheckoutBank.class);
public CheckoutBank(Node bank) { public CheckoutBank(Node bank) {
if (bank.getNodeType() != 1) if (bank.getNodeType() != Node.ELEMENT_NODE) {
{
throw new RuntimeException("Wrong type of node " + bank + " type " + bank.getNodeType()); throw new RuntimeException("Wrong type of node " + bank + " type " + bank.getNodeType());
} }
key = bank.getNodeName(); key = bank.getNodeName();
...@@ -47,8 +46,7 @@ public class CheckoutBank { ...@@ -47,8 +46,7 @@ public class CheckoutBank {
String iconval = null; String iconval = null;
String nameval = null; String nameval = null;
String urlval = null; String urlval = null;
for (int j = 0; j < attrs.getLength(); ++j) for (int j = 0; j < attrs.getLength(); ++j) {
{
Node attr = attrs.item(j); Node attr = attrs.item(j);
if (attr.getNodeName().equals("icon")) { if (attr.getNodeName().equals("icon")) {
iconval = attr.getNodeValue(); iconval = attr.getNodeValue();
...@@ -63,18 +61,14 @@ public class CheckoutBank { ...@@ -63,18 +61,14 @@ public class CheckoutBank {
url = urlval; url = urlval;
NodeList children = bank.getChildNodes(); NodeList children = bank.getChildNodes();
for (int i = 0; i < children.getLength(); ++i) for (int i = 0; i < children.getLength(); ++i) {
{
Node childnode = children.item(i); Node childnode = children.item(i);
if (childnode.getNodeType() == 1) if (childnode.getNodeType() == Node.ELEMENT_NODE) {
{
String paramName = childnode.getNodeName(); String paramName = childnode.getNodeName();
String paramValue = childnode.getTextContent(); String paramValue = childnode.getTextContent();
getPostParams().add(new Valuepair(paramName, paramValue)); getPostParams().add(new Valuepair(paramName, paramValue));
logger.info("Added param for {} name {} value {}", new Object[] { key, paramName, paramValue });
} }
} }
// System.out.println();
} }
......
...@@ -18,14 +18,18 @@ ...@@ -18,14 +18,18 @@
*/ */
package fi.codecrew.moya.beans; package fi.codecrew.moya.beans;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.EnumMap;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
...@@ -41,13 +45,12 @@ import javax.xml.parsers.DocumentBuilder; ...@@ -41,13 +45,12 @@ import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair; import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair; import org.apache.http.message.BasicNameValuePair;
import org.slf4j.Logger; import org.slf4j.Logger;
...@@ -58,7 +61,9 @@ import org.w3c.dom.Node; ...@@ -58,7 +61,9 @@ import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import fi.codecrew.moya.checkoutfi.CheckoutFiCheckParam;
import fi.codecrew.moya.checkoutfi.CheckoutFiParam; import fi.codecrew.moya.checkoutfi.CheckoutFiParam;
import fi.codecrew.moya.checkoutfi.CheckoutQuery;
import fi.codecrew.moya.clientutils.BortalLocalContextHolder; import fi.codecrew.moya.clientutils.BortalLocalContextHolder;
import fi.codecrew.moya.enums.apps.BillPermission; import fi.codecrew.moya.enums.apps.BillPermission;
import fi.codecrew.moya.facade.BillFacade; import fi.codecrew.moya.facade.BillFacade;
...@@ -99,7 +104,66 @@ public class CheckoutFiBean implements CheckoutFiBeanLocal { ...@@ -99,7 +104,66 @@ public class CheckoutFiBean implements CheckoutFiBeanLocal {
private BillPBean billpbean; private BillPBean billpbean;
private static final Logger logger = LoggerFactory.getLogger(CheckoutFiBean.class); private static final Logger logger = LoggerFactory.getLogger(CheckoutFiBean.class);
private static final BigDecimal TO_CENTS = BigDecimal.valueOf(100); static final BigDecimal TO_CENTS = BigDecimal.valueOf(100);
static final String DATEFORMAT = "yyyyMMdd";
static final Set<String> DISCARD_BANKS = new HashSet<String>(Arrays.asList("ape", "tilisiirto", "neopay"));
/**
* Notice! This is a long running function which creates a remote HTTP
* query.
*
*/
public boolean isBillPaid(Bill bill) {
QueryBuilder<CheckoutFiCheckParam> cb = initQuerybuilder(CheckoutFiCheckParam.class, CheckoutFiCheckParam.values());
if (!cb.isCredentialsValid()) {
throw new EJBException("Invalid Credentials");
}
final String priceInCents = Integer.valueOf(bill.totalPrice().multiply(TO_CENTS).intValue()).toString();
cb.addParam(CheckoutFiCheckParam.STAMP, getStamp(bill));
cb.addParam(CheckoutFiCheckParam.REFERENCE, bill.getReferenceNumber().toString());
cb.addParam(CheckoutFiCheckParam.MERCHANT, cb.getMerchantId());
cb.addParam(CheckoutFiCheckParam.AMOUNT, priceInCents);
CloseableHttpResponse response = null;
boolean ret = false;
try {
response = sendQuery(cb);
InputStream queryContent = response.getEntity().getContent();
String returnValue = parsePollXml(queryContent);
int statusInt = Integer.parseInt(returnValue);
// Verkkokauppaohjelmisto voi hyväksyä maksun suoritetuksi
// kun maksun tila on 2,5,6,7,8,9 tai 10.
switch (statusInt) {
case 2:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
ret = true;
break;
default:
}
} catch (IOException e) {
logger.warn("Error sending checkout.fi request", e);
} finally {
try {
if (response != null) {
response.close();
}
} catch (IOException e) {
logger.warn("Error closing checkout.fi request", e);
}
}
return ret;
}
@Override @Override
public boolean isPaymentEnabled() public boolean isPaymentEnabled()
...@@ -107,215 +171,171 @@ public class CheckoutFiBean implements CheckoutFiBeanLocal { ...@@ -107,215 +171,171 @@ public class CheckoutFiBean implements CheckoutFiBeanLocal {
final LanEventPrivateProperty expire = eventbean.getPrivateProperty(LanEventPrivatePropertyKey.CHECKOUT_FI_KEY_EXPIRE); final LanEventPrivateProperty expire = eventbean.getPrivateProperty(LanEventPrivatePropertyKey.CHECKOUT_FI_KEY_EXPIRE);
final String merchantid = eventbean.getPrivatePropertyString(LanEventPrivatePropertyKey.CHECKOUT_FI_MERCHANT_ID); final String merchantid = eventbean.getPrivatePropertyString(LanEventPrivatePropertyKey.CHECKOUT_FI_MERCHANT_ID);
final String merchantPassword = eventbean.getPrivatePropertyString(LanEventPrivatePropertyKey.CHECKOUT_FI_MERCHANT_PASSWORD); final String merchantPassword = eventbean.getPrivatePropertyString(LanEventPrivatePropertyKey.CHECKOUT_FI_MERCHANT_PASSWORD);
return !((expire != null && new Date().after(expire.getDateValue())) final boolean expired = (expire == null || expire.getDateValue() == null || new Date().after(expire.getDateValue()));
|| merchantid == null || merchantid.isEmpty()
|| merchantPassword == null || merchantPassword.isEmpty()); boolean ret = !expired
&& merchantid != null && !merchantid.isEmpty()
&& merchantPassword != null && !merchantPassword.isEmpty();
return ret;
} }
public static void main(String[] asd) throws ParserConfigurationException, SAXException, IOException protected <T extends Enum<T>> QueryBuilder<T> initQuerybuilder(Class<T> clz, CheckoutQuery[] params) {
{
// DocumentBuilderFactory dbFactory =
// DocumentBuilderFactory.newInstance();
// DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
// Document doc = dBuilder.parse(xmlstr);
// // DOMParser parser = new DOMParser();
// // Document doc = parser.getDocument();
// // parser.parse(new InputSource(new StringReader(xmlReturn)));
// Element root = doc.getDocumentElement();
// root.normalize();
// // NodeList rootChildren = root.getChildNodes();
// // for (int i = 0; i < rootChildren.getLength(); ++i)
// // {
// // logger.info("Rootchild {}", rootChildren.item(i).getNodeName());
// // }
//
// Node payments = root.getElementsByTagName("banks").item(0);
final LanEventPrivateProperty expire = eventbean.getPrivateProperty(LanEventPrivatePropertyKey.CHECKOUT_FI_KEY_EXPIRE);
final String merchantid = eventbean.getPrivatePropertyString(LanEventPrivatePropertyKey.CHECKOUT_FI_MERCHANT_ID);
final String merchantPassword = eventbean.getPrivatePropertyString(LanEventPrivatePropertyKey.CHECKOUT_FI_MERCHANT_PASSWORD);
Date date = null;
if (expire != null) {
date = expire.getDateValue();
} }
QueryBuilder<T> ret = new QueryBuilder<T>(clz, params, date, merchantid, merchantPassword);
return ret;
private static final String DATEFORMAT = "yyyyMMdd"; }
private static final Set<String> DISCARD_BANKS = new HashSet<String>(Arrays.asList("ape", "tilisiirto", "neopay"));
@Override @Override
@RolesAllowed(BillPermission.S_CREATE_VERKKOMAKSU) @RolesAllowed(BillPermission.S_CREATE_VERKKOMAKSU)
public List<CheckoutBank> getToken(Bill bill) public List<CheckoutBank> getToken(Bill bill)
{ {
if (bill.isFoowavePaymentOver()) if (bill.isFoowavePaymentOver()) {
{
return null; return null;
} }
QueryBuilder<CheckoutFiParam> queryBuilder = initQuerybuilder(CheckoutFiParam.class, CheckoutFiParam.values());
final LanEventPrivateProperty expire = eventbean.getPrivateProperty(LanEventPrivatePropertyKey.CHECKOUT_FI_KEY_EXPIRE); if (!queryBuilder.isCredentialsValid()) {
final String merchantid = eventbean.getPrivatePropertyString(LanEventPrivatePropertyKey.CHECKOUT_FI_MERCHANT_ID);
final String merchantPassword = eventbean.getPrivatePropertyString(LanEventPrivatePropertyKey.CHECKOUT_FI_MERCHANT_PASSWORD);
if ((expire != null && new Date().after(expire.getDateValue()))
|| merchantid == null || merchantid.isEmpty()
|| merchantPassword == null || merchantPassword.isEmpty())
{
return null; return null;
} }
final String priceInCents = Integer.valueOf(bill.totalPrice().multiply(TO_CENTS).intValue()).toString();
final Map<CheckoutFiParam, String> postParams = new HashMap<CheckoutFiParam, String>();
final String returnUrl = new StringBuilder(BortalLocalContextHolder.isSsl() ? "https://" : "http://") final String returnUrl = new StringBuilder()
.append(BortalLocalContextHolder.isSsl() ? "https://" : "http://")
.append(BortalLocalContextHolder.getHostname()) .append(BortalLocalContextHolder.getHostname())
.append("/MoyaWeb/checkout/") .append("/MoyaWeb/checkout/")
.toString(); .toString();
final StringBuilder stamp = new StringBuilder(); final String priceInCents = Integer.valueOf(bill.totalPrice().multiply(TO_CENTS).intValue()).toString();
stamp.append(bill.getId());
stamp.append(STAMP_SPLITCHAR);
stamp.append(bill.getSentDate().getTimeInMillis() / 1000);
postParams.put(CheckoutFiParam.STAMP, stamp.toString()); queryBuilder.addParam(CheckoutFiParam.STAMP, getStamp(bill));
postParams.put(CheckoutFiParam.AMOUNT, priceInCents); queryBuilder.addParam(CheckoutFiParam.AMOUNT, priceInCents);
postParams.put(CheckoutFiParam.REFERENCE, bill.getReferenceNumber().toString()); queryBuilder.addParam(CheckoutFiParam.REFERENCE, bill.getReferenceNumber().toString());
postParams.put(CheckoutFiParam.MERCHANT, merchantid); queryBuilder.addParam(CheckoutFiParam.MERCHANT, queryBuilder.getMerchantId());
postParams.put(CheckoutFiParam.RETURN, returnUrl + "return.jsf"); queryBuilder.addParam(CheckoutFiParam.RETURN, returnUrl + "return.jsf");
postParams.put(CheckoutFiParam.CANCEL, returnUrl + "cancel.jsf"); queryBuilder.addParam(CheckoutFiParam.CANCEL, returnUrl + "cancel.jsf");
postParams.put(CheckoutFiParam.REJECT, returnUrl + "reject.jsf"); queryBuilder.addParam(CheckoutFiParam.REJECT, returnUrl + "reject.jsf");
postParams.put(CheckoutFiParam.DELAYED, returnUrl + "delayed.jsf"); queryBuilder.addParam(CheckoutFiParam.DELAYED, returnUrl + "delayed.jsf");
postParams.put(CheckoutFiParam.DELIVERY_DATE, new SimpleDateFormat(DATEFORMAT).format(new Date())); queryBuilder.addParam(CheckoutFiParam.DELIVERY_DATE, new SimpleDateFormat(DATEFORMAT).format(new Date()));
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(); CloseableHttpResponse response = null;
StringBuilder mdString = new StringBuilder(); List<CheckoutBank> ret = null;
InputStream queryContent = null;
for (CheckoutFiParam v : CheckoutFiParam.values()) try {
{ response = sendQuery(queryBuilder);
String value = null; queryContent = response.getEntity().getContent();
if (postParams.containsKey(v)) { ret = parseTokenXml(queryContent);
value = postParams.get(v); } catch (IOException e) {
} else { logger.warn("Error sending checkout.fi request", e);
value = v.getDefaultValue(); } finally {
try {
if (queryContent != null)
queryContent.close();
} catch (IOException e1) {
logger.warn("Error closing checkout.fi inputstream", e1);
} }
if (value != null) { try {
mdString.append(value); if (response != null) {
nameValuePairs.add(new BasicNameValuePair(v.name(), value)); response.close();
}
} catch (IOException e) {
logger.warn("Error closing checkout.fi request", e);
} }
mdString.append("+");
} }
mdString.append(merchantPassword);
CloseableHttpResponse response = null;
try {
final String calculatedHash = PasswordFunctions.calculateMd5(mdString.toString()); return ret;
logger.info("Calculated checksum {} from {}",
mdString.toString(), calculatedHash);
nameValuePairs.add(new BasicNameValuePair("MAC", calculatedHash)); }
private static CloseableHttpResponse sendQuery(QueryBuilder<?> queryBuilder) throws ClientProtocolException, IOException {
CloseableHttpResponse response = null;
final HttpPost postRequest = new HttpPost(REMOTE_URL); final HttpPost postRequest = new HttpPost(REMOTE_URL);
postRequest.setEntity(new UrlEncodedFormEntity(nameValuePairs)); postRequest.setEntity(new UrlEncodedFormEntity(queryBuilder.getNameValuePairs()));
HttpClientBuilder cliBuilder = HttpClientBuilder.create(); HttpClientBuilder cliBuilder = HttpClientBuilder.create();
CloseableHttpClient cli = cliBuilder.build(); CloseableHttpClient cli = cliBuilder.build();
response = cli.execute(postRequest); response = cli.execute(postRequest);
// final DefaultHttpClient client = new DefaultHttpClient(); return response;
// HttpResponse response = client.execute(postRequest); }
// final StringWriter writer = new StringWriter();
//
// IOUtils.copy(, writer, "UTF8");
//
// final String xmlReturn = writer.toString();
// // logger.info("Got response from checkout.fi msg {}, {} ",
// // response.getStatusLine().getStatusCode(), xmlReturn);
return parseTokenXml(response.getEntity().getContent()); static final String getStamp(Bill bill) {
final StringBuilder stamp = new StringBuilder();
stamp.append(bill.getId());
stamp.append(STAMP_SPLITCHAR);
stamp.append(bill.getSentDate().getTimeInMillis() / 1000);
return stamp.toString();
}
} catch (IOException e) { protected static String parsePollXml(InputStream queryContent) {
logger.warn("Error sending checkout.fi request", e); String ret = null;
} finally {
try { try {
if (response != null) { DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
response.close(); DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(queryContent);
Element root = doc.getDocumentElement();
// root.normalize();
Node status = root.getElementsByTagName("status").item(0);
if (status != null) {
ret = status.getTextContent();
if (ret != null) {
ret = ret.trim();
} }
} catch (IOException e) {
logger.warn("Error closing checkout.fi request", e);
} }
} catch (SAXException | IOException | ParserConfigurationException e) {
ret = null;
logger.warn("Error parsing response from checkout response:", e);
} }
return ret;
return null;
} }
// @Override protected static List<CheckoutBank> parseTokenXml(InputStream inputStream) {
// public List<CheckoutBank> testXml()
// {
// List<CheckoutBank> ret = null;
// try {
// BufferedReader reader = new BufferedReader(new
// FileReader("/Users/tuomari/Documents/git/bortal/code/LanBortalBeans/ejbModule/fi.codecrew.moya/beans/checkoutTestfile.xml"));
// StringBuilder sb = new StringBuilder();
//
// String line = null;
// while ((line = reader.readLine()) != null) {
// sb.append(line);
// sb.append("\n");
// }
//
// reader.close();
// String str = sb.toString();
// ret = parseTokenXml(str);
//
// } catch (Throwable t)
// {
// logger.warn("error testing", t);
// }
// // logger.warn("str: {}", str);
// return ret;
// }
private static List<CheckoutBank> parseTokenXml(InputStream inputStream) {
try { try {
// DOMParser parser = new DOMParser();
// parser.parse(new InputSource(new StringReader(xmlReturn)));
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
// InputStream xmlstr = IOUtils.toInputStream(inputStream);
Document doc = dBuilder.parse(inputStream); Document doc = dBuilder.parse(inputStream);
// Document doc = parser.getDocument();
Element root = doc.getDocumentElement(); Element root = doc.getDocumentElement();
root.normalize(); root.normalize();
// NodeList rootChildren = root.getChildNodes();
// for (int i = 0; i < rootChildren.getLength(); ++i)
// {
// logger.info("Rootchild {}", rootChildren.item(i).getNodeName());
// }
Node payments = root.getElementsByTagName("banks").item(0); Node payments = root.getElementsByTagName("banks").item(0);
NodeList paymentElements = payments.getChildNodes(); NodeList paymentElements = payments.getChildNodes();
List<CheckoutBank> retbanks = new ArrayList<CheckoutBank>(); List<CheckoutBank> retbanks = new ArrayList<CheckoutBank>();
for (int i = 0; i < paymentElements.getLength(); ++i) for (int i = 0; i < paymentElements.getLength(); ++i) {
{
Node bank = paymentElements.item(i); Node bank = paymentElements.item(i);
if (bank.getNodeType() == 1) if (bank.getNodeType() == 1) {
{
CheckoutBank newBank = new CheckoutBank(bank); CheckoutBank newBank = new CheckoutBank(bank);
if (!DISCARD_BANKS.contains(newBank.getKey())) if (!DISCARD_BANKS.contains(newBank.getKey())) {
{
retbanks.add(newBank); retbanks.add(newBank);
} }
} }
} }
return retbanks; return retbanks;
} catch (SAXException | IOException | ParserConfigurationException e) { } catch (SAXException | IOException | ParserConfigurationException e) {
logger.warn("Error parsing response from checkout response:" + inputStream, e); logger.warn("Error parsing response from checkout response:" + inputStream, e);
} finally {
try {
inputStream.close();
} catch (IOException e) {
logger.warn("Error closing the input stream", e);
} }
}
return null; return null;
} }
@Override @Override
public boolean validateReturn(CheckoutReturnType returnType, String version, String stamp, String reference, String payment, String status, String algorithm, String mac) { public boolean validateReturn(CheckoutReturnType returnType, String version, String stamp, String reference, String payment, String status, String algorithm, String mac) {
if (returnType == null || mac == null || mac.isEmpty() || stamp == null || stamp.isEmpty()) if (returnType == null || mac == null || mac.isEmpty() || stamp == null || stamp.isEmpty()) {
{
return false; return false;
} }
String merchantPass = eventbean.getPrivatePropertyString(LanEventPrivatePropertyKey.CHECKOUT_FI_MERCHANT_PASSWORD); String merchantPass = eventbean.getPrivatePropertyString(LanEventPrivatePropertyKey.CHECKOUT_FI_MERCHANT_PASSWORD);
...@@ -363,13 +383,12 @@ public class CheckoutFiBean implements CheckoutFiBeanLocal { ...@@ -363,13 +383,12 @@ public class CheckoutFiBean implements CheckoutFiBeanLocal {
case 8: case 8:
case 9: case 9:
case 10: case 10:
ret = true;
if (bill.getAccountEvent() == null if (bill.getAccountEvent() == null
&& bill.getPaidDate() == null) && bill.getPaidDate() == null) {
{
logger.info("Trying to mark bill {} paid", bill); logger.info("Trying to mark bill {} paid", bill);
billpbean.markPaid(bill, Calendar.getInstance(), false); billpbean.markPaid(bill, Calendar.getInstance(), false);
logbean.sendMessage(MoyaEventType.BANKING_MESSAGE, permbean.getCurrentUser(), "Marking bill paid from checkout. Received bill status ", statusInt, " for bill ", bill, " stamp ", stamp, " payment: ", payment, " reference ", reference); logbean.sendMessage(MoyaEventType.BANKING_MESSAGE, permbean.getCurrentUser(), "Marking bill paid from checkout. Received bill status ", statusInt, " for bill ", bill, " stamp ", stamp, " payment: ", payment, " reference ", reference);
ret = true;
} else { } else {
logbean.sendMessage(MoyaEventType.BANKING_MESSAGE, permbean.getCurrentUser(), "Bill already marked paid: ", bill, " status ", status, " stamp ", stamp, " payment ", payment); logbean.sendMessage(MoyaEventType.BANKING_MESSAGE, permbean.getCurrentUser(), "Bill already marked paid: ", bill, " status ", status, " stamp ", stamp, " payment ", payment);
} }
...@@ -396,4 +415,67 @@ public class CheckoutFiBean implements CheckoutFiBeanLocal { ...@@ -396,4 +415,67 @@ public class CheckoutFiBean implements CheckoutFiBeanLocal {
return ret; return ret;
} }
static class QueryBuilder<T extends Enum<T>> {
private final Map<CheckoutQuery, String> values = new HashMap<>();;
private final Date expireDate;
private final String merchantId;
private final String merchantPassword;
private final CheckoutQuery[] types;
QueryBuilder(Class<T> clz, CheckoutQuery[] types, Date expire, String merchantId, String merchantPassword) {
this.expireDate = expire;
this.merchantId = merchantId;
this.merchantPassword = merchantPassword;
this.types = types;
}
public boolean isCredentialsValid() {
return expireDate != null && new Date().before(expireDate)
&& getMerchantId() != null && !getMerchantId().isEmpty()
&& merchantPassword != null && !merchantPassword.isEmpty();
}
public void addParam(CheckoutQuery key, String value) {
values.put(key, value);
}
public List<NameValuePair> getNameValuePairs() {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
StringBuilder mdString = new StringBuilder();
for (CheckoutQuery v : types) {
String value = null;
if (values.containsKey(v)) {
value = values.get(v);
} else {
value = v.getDefaultValue();
}
logger.info("Add key {},value {}", v.name(), value);
if (value != null) {
mdString.append(value);
nameValuePairs.add(new BasicNameValuePair(v.name(), value));
}
mdString.append("+");
}
mdString.append(merchantPassword);
final String calculatedHash = PasswordFunctions.calculateMd5(mdString.toString());
logger.info("Calculated checksum {} from {}", mdString.toString(), calculatedHash);
nameValuePairs.add(new BasicNameValuePair("MAC", calculatedHash));
return nameValuePairs;
}
public String getMerchantId() {
return merchantId;
}
}
} }
package fi.codecrew.moya.checkoutfi;
public enum CheckoutFiCheckParam implements CheckoutQuery {
// DO NOT CHANGE THE ORDER OF THESE!
// The md5 checksum is calculated from
// these values...
VERSION("0001"),
STAMP(null),
REFERENCE(null),
MERCHANT(null),
AMOUNT(null),
CURRENCY("EUR"),
FORMAT("1"),
ALGORITHM("1"),
// MAC gets added automatically in querybuilder
;
private final String defaultValue;
private CheckoutFiCheckParam(String def) {
defaultValue = def;
}
public String getDefaultValue() {
return defaultValue;
}
}
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
*/ */
package fi.codecrew.moya.checkoutfi; package fi.codecrew.moya.checkoutfi;
public enum CheckoutFiParam { public enum CheckoutFiParam implements CheckoutQuery {
// DO NOT CHANGE THE ORDER OF THESE! // DO NOT CHANGE THE ORDER OF THESE!
// The md5 checksum is calculated from // The md5 checksum is calculated from
...@@ -45,7 +45,10 @@ public enum CheckoutFiParam { ...@@ -45,7 +45,10 @@ public enum CheckoutFiParam {
FAMILYNAME(null), FAMILYNAME(null),
ADDRESS(null), ADDRESS(null),
POSTCODE(null), POSTCODE(null),
POSTOFFICE(null), ; POSTOFFICE(null),
// MAC gets added automatically in querybuilder
;
private final String defaultValue; private final String defaultValue;
......
package fi.codecrew.moya.checkoutfi;
public interface CheckoutQuery {
public String name();
public String getDefaultValue();
}
package fi.codecrew.moya.beans;
import static org.testng.AssertJUnit.*;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.FileReader;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.http.NameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.Test;
import fi.codecrew.moya.beans.CheckoutFiBean.QueryBuilder;
import fi.codecrew.moya.checkoutfi.CheckoutFiParam;
import fi.codecrew.moya.clientutils.BortalLocalContextHolder;
import fi.codecrew.moya.model.Bill;
import fi.codecrew.moya.model.BillLine;
import fi.codecrew.moya.model.LanEvent;
import fi.codecrew.moya.model.Product;
import fi.codecrew.moya.util.CheckoutBank;
@Test
public class CheckoutFiBeanTests extends CheckoutFiBean {
private static final Logger logger = LoggerFactory.getLogger(CheckoutFiBeanTests.class);
@Test
public void testQuery() {
QueryBuilder<CheckoutFiParam> queryBuilder = new QueryBuilder<CheckoutFiParam>(CheckoutFiParam.class, CheckoutFiParam.values(), new Date(System.currentTimeMillis() + 60000), "375917", "SAIPPUAKAUPPIAS");
assertTrue("Credentials are valid!", queryBuilder.isCredentialsValid());
final String returnUrl = new StringBuilder()
.append("https://")
.append("localhost")
.append("/MoyaWeb/checkout/")
.toString();
LanEvent lanevent = new LanEvent();
lanevent.setReferenceNumberBase(100000);
Date d = new Date(1427495053008l);
Bill bill = new Bill();
bill.setEvent(lanevent);
bill.setId(67890);
bill.setBillNumber(12345);
bill.setAddr1("Teemu Teekkari");
bill.setAddr2("Hervannantie 1");
bill.setAddr3("33600 Tampere");
bill.setAddr4("FINLAND");
bill.setSentDateTime(d);
Product prod = new Product();
prod.setName("Hurr");
prod.setPrice(new BigDecimal(111.11).setScale(4, RoundingMode.HALF_UP));
bill.getBillLines().add(new BillLine(bill, prod, new BigDecimal(5)));
logger.info("Total price{}" + bill.getTotalPrice());
final String priceInCents = Integer.valueOf(bill.totalPrice().multiply(TO_CENTS).intValue()).toString();
final Map<String, String> requiredParams = new HashMap<>();
requiredParams.put("VERSION", "0001");
requiredParams.put("COUNTRY", "FIN");
requiredParams.put("CURRENCY", "EUR");
requiredParams.put("DEVICE", "10");
requiredParams.put("CONTENT", "1");
requiredParams.put("TYPE", "0");
requiredParams.put("ALGORITHM", "2");
requiredParams.put("LANGUAGE", "FI");
queryBuilder.addParam(CheckoutFiParam.STAMP, getStamp(bill));
requiredParams.put("STAMP", "67890a1427495053");
queryBuilder.addParam(CheckoutFiParam.AMOUNT, priceInCents);
requiredParams.put("AMOUNT", "55555");
queryBuilder.addParam(CheckoutFiParam.REFERENCE, bill.getReferenceNumber().toString());
// 112345 + checksum(2)
requiredParams.put("REFERENCE", "1123452");
queryBuilder.addParam(CheckoutFiParam.MERCHANT, queryBuilder.getMerchantId());
requiredParams.put("MERCHANT", "375917");
queryBuilder.addParam(CheckoutFiParam.RETURN, returnUrl + "return.jsf");
requiredParams.put("RETURN", "https://localhost/MoyaWeb/checkout/return.jsf");
queryBuilder.addParam(CheckoutFiParam.CANCEL, returnUrl + "cancel.jsf");
requiredParams.put("CANCEL", "https://localhost/MoyaWeb/checkout/cancel.jsf");
queryBuilder.addParam(CheckoutFiParam.REJECT, returnUrl + "reject.jsf");
requiredParams.put("REJECT", "https://localhost/MoyaWeb/checkout/reject.jsf");
queryBuilder.addParam(CheckoutFiParam.DELAYED, returnUrl + "delayed.jsf");
requiredParams.put("DELAYED", "https://localhost/MoyaWeb/checkout/delayed.jsf");
queryBuilder.addParam(CheckoutFiParam.DELIVERY_DATE, new SimpleDateFormat(DATEFORMAT).format(d));
requiredParams.put("DELIVERY_DATE", "20150328");
requiredParams.put("MAC", "7FBDC5A633794B7292E6B02020330E64");
List<NameValuePair> nvpairs = queryBuilder.getNameValuePairs();
for (NameValuePair p : nvpairs) {
assertTrue("Missing required param: " + p.getName() + " val " + p.getValue(), requiredParams.containsKey(p.getName()));
String val = requiredParams.remove(p.getName());
assertEquals("Wrong value for " + p.getName(), val, p.getValue());
}
for (Entry<String, String> p : requiredParams.entrySet()) {
logger.warn("Not found param {} with value {}", p.getKey(), p.getValue());
}
}
@Test
public void testXml()
{
InputStream testfile1 = getClass().getResourceAsStream("checkoutTestfile.xml");
List<CheckoutBank> ret = CheckoutFiBean.parseTokenXml(testfile1);
// Huom! Neopay, ape ja tilisiirto poistettu parsinnassa.
assertEquals(8, ret.size());
for (int i = 0; i < ret.size(); ++i) {
CheckoutBank bnk = ret.get(i);
switch (i) {
case 0:
assertEquals("nordea", bnk.getKey());
assertEquals(17, bnk.getPostParams().size());
break;
case 1:
assertEquals("osuuspankki", bnk.getKey());
assertEquals(13, bnk.getPostParams().size());
break;
case 2:
assertEquals("samlink", bnk.getKey());
assertEquals(13, bnk.getPostParams().size());
break;
case 3:
assertEquals("sampo", bnk.getKey());
assertEquals(9, bnk.getPostParams().size());
break;
case 4:
assertEquals("handelsbanken", bnk.getKey());
assertEquals(13, bnk.getPostParams().size());
break;
case 5:
assertEquals("spankki", bnk.getKey());
assertEquals(17, bnk.getPostParams().size());
break;
case 6:
assertEquals("alandsbanken", bnk.getKey());
assertEquals(18, bnk.getPostParams().size());
break;
case 7:
assertEquals("tapiola", bnk.getKey());
assertEquals(18, bnk.getPostParams().size());
break;
case 8:
assertEquals("neopay", bnk.getKey());
assertEquals(9, bnk.getPostParams().size());
break;
case 9:
assertEquals("tilisiirto", bnk.getKey());
assertEquals(6, bnk.getPostParams().size());
break;
case 10:
assertEquals("ape", bnk.getKey());
assertEquals(4, bnk.getPostParams().size());
break;
default:
fail("Wrong number of banks: " + i);
break;
}
}
}
private static final String pollReturnXML = "<?xml version=\"1.0\"?> <trade> <status> 2 </status></trade> ";
private static final String LATIN1 = "ISO-8859-1";
@Test
public void testPollXml() throws UnsupportedEncodingException
{
String ret = CheckoutFiBean.parsePollXml(new ByteArrayInputStream(pollReturnXML.getBytes(LATIN1)));
assertEquals("2", ret);
}
}
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!