Skip to content

Commit ebde3c3

Browse files
authored
Merge pull request #17 from bcgov/feature/payment-services
Adding Bambora Implementation
2 parents f0571d5 + 47e5074 commit ebde3c3

File tree

13 files changed

+482
-0
lines changed

13 files changed

+482
-0
lines changed

src/bambora-payment-starter/README.md

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Read Me First
2+
The following was discovered as part of building this project:
3+
4+
* The original package name 'ca.bc.gov.open.bambora-payment-starter' is invalid and this project uses 'ca.bc.gov.open.bamborapaymentstarter' instead.
5+
6+
# Getting Started
7+
8+
### Reference Documentation
9+
For further reference, please consider the following sections:
10+
11+
* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html)
12+
* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.3.3.RELEASE/maven-plugin/reference/html/)
13+
* [Create an OCI image](https://docs.spring.io/spring-boot/docs/2.3.3.RELEASE/maven-plugin/reference/html/#build-image)
14+

src/bambora-payment-starter/pom.xml

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<groupId>ca.bc.gov.open</groupId>
7+
<artifactId>bambora-payment-starter</artifactId>
8+
<version>0.1.5</version>
9+
10+
<properties>
11+
<java.version>1.8</java.version>
12+
<spring-boot.version>2.2.4.RELEASE</spring-boot.version>
13+
</properties>
14+
15+
<dependencies>
16+
<dependency>
17+
<groupId>org.springframework.boot</groupId>
18+
<artifactId>spring-boot-starter-web-services</artifactId>
19+
<exclusions>
20+
<exclusion>
21+
<groupId>org.springframework.boot</groupId>
22+
<artifactId>spring-boot-starter-tomcat</artifactId>
23+
</exclusion>
24+
</exclusions>
25+
</dependency>
26+
27+
<dependency>
28+
<groupId>org.springframework.boot</groupId>
29+
<artifactId>spring-boot-starter-test</artifactId>
30+
<scope>test</scope>
31+
<exclusions>
32+
<exclusion>
33+
<groupId>org.junit.vintage</groupId>
34+
<artifactId>junit-vintage-engine</artifactId>
35+
</exclusion>
36+
</exclusions>
37+
</dependency>
38+
39+
<dependency>
40+
<groupId>org.apache.commons</groupId>
41+
<artifactId>commons-lang3</artifactId>
42+
</dependency>
43+
44+
<dependency>
45+
<groupId>commons-codec</groupId>
46+
<artifactId>commons-codec</artifactId>
47+
</dependency>
48+
49+
</dependencies>
50+
51+
<dependencyManagement>
52+
<dependencies>
53+
<dependency>
54+
<groupId>org.springframework.boot</groupId>
55+
<artifactId>spring-boot-dependencies</artifactId>
56+
<version>${spring-boot.version}</version>
57+
<type>pom</type>
58+
<scope>import</scope>
59+
</dependency>
60+
<dependency>
61+
<groupId>ca.bc.gov.open</groupId>
62+
<artifactId>spring-starters-bom</artifactId>
63+
<version>0.1.5</version>
64+
<type>pom</type>
65+
<scope>import</scope>
66+
</dependency>
67+
</dependencies>
68+
</dependencyManagement>
69+
70+
<build>
71+
<plugins>
72+
<plugin>
73+
<groupId>org.apache.maven.plugins</groupId>
74+
<artifactId>maven-compiler-plugin</artifactId>
75+
<version>3.5.1</version>
76+
<configuration>
77+
<source>${java.version}</source>
78+
<target>${java.version}</target>
79+
</configuration>
80+
</plugin>
81+
</plugins>
82+
</build>
83+
84+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package ca.bc.gov.open.bambora.payment.starter;
2+
3+
import ca.bc.gov.open.bambora.payment.starter.managment.BamboraCardService;
4+
import ca.bc.gov.open.bambora.payment.starter.managment.BamboraCardServiceImpl;
5+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
6+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
7+
import org.springframework.context.annotation.Bean;
8+
import org.springframework.context.annotation.Configuration;
9+
10+
@Configuration
11+
@EnableConfigurationProperties(BamboraProperties.class)
12+
public class AutoConfiguration {
13+
14+
private final BamboraProperties bamboraProperties;
15+
16+
public AutoConfiguration(BamboraProperties bamboraProperties) {
17+
this.bamboraProperties = bamboraProperties;
18+
}
19+
20+
@Bean
21+
@ConditionalOnMissingBean(BamboraCardService.class)
22+
public BamboraCardService bamboraCardService() {
23+
return new BamboraCardServiceImpl(bamboraProperties);
24+
}
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package ca.bc.gov.open.bambora.payment.starter;
2+
3+
public class BamboraConstants {
4+
public static final String PARAM_PPRDIR_SERVICE_VERSION = "serviceVersion";
5+
public static final String PARAM_PPRDIR_MERCHANT_ID = "merchantId";
6+
public static final String PARAM_PPRDIR_LANGUAGE = "trnLanguage";
7+
public static final String PARAM_PPRDIR_OPERATION_TYPE = "operationType";
8+
public static final String PARAM_PPRDIR_RETURN_URL = "trnReturnURL";
9+
public static final String PARAM_PPRDIR_ORDER_NUMBER = "trnOrderNumber";
10+
public static final String PARAM_PPRDIR_CUSTOMER_CODE = "customerCode";
11+
public static final String PARAM_PPRDIR_REF1 = "ref1";
12+
public static final String LANGUAGE_TYPE = "eng";
13+
public static final String PARAM_TRANS_HASH_VALUE = "hashValue";
14+
public static final String PARAM_TRANS_HASH_EXPIRY = "hashExpiry";
15+
public static final String PARAM_TRANS_HASH_EXPIRY_FORMAT = "yyyyMMddkkmm";
16+
17+
18+
public enum OperationTypes {
19+
N, M
20+
}
21+
22+
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package ca.bc.gov.open.bambora.payment.starter;
2+
3+
public class BamboraException extends RuntimeException {
4+
5+
public BamboraException(String message, Throwable cause) {
6+
super(message, cause);
7+
}
8+
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package ca.bc.gov.open.bambora.payment.starter;
2+
3+
import org.springframework.boot.context.properties.ConfigurationProperties;
4+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
5+
import org.springframework.context.annotation.Configuration;
6+
7+
@Configuration
8+
@EnableConfigurationProperties(BamboraProperties.class)
9+
@ConfigurationProperties(prefix = "bambora")
10+
public class BamboraProperties {
11+
private String merchantId;
12+
private String hostedProfileUrl;
13+
private String hostedProfileServiceVersion;
14+
private String hashKey;
15+
private int minutesToExpiry;
16+
17+
public String getMerchantId() {
18+
return merchantId;
19+
}
20+
21+
public void setMerchantId(String merchantId) {
22+
this.merchantId = merchantId;
23+
}
24+
25+
public String getHostedProfileUrl() {
26+
return hostedProfileUrl;
27+
}
28+
29+
public void setHostedProfileUrl(String hostedProfileUrl) {
30+
this.hostedProfileUrl = hostedProfileUrl;
31+
}
32+
33+
public String getHostedProfileServiceVersion() {
34+
return hostedProfileServiceVersion;
35+
}
36+
37+
public void setHostedProfileServiceVersion(String hostedProfileServiceVersion) {
38+
this.hostedProfileServiceVersion = hostedProfileServiceVersion;
39+
}
40+
41+
public String getHashKey() {
42+
return hashKey;
43+
}
44+
45+
public void setHashKey(String hashKey) {
46+
this.hashKey = hashKey;
47+
}
48+
49+
public int getMinutesToExpiry() {
50+
return minutesToExpiry;
51+
}
52+
53+
public void setMinutesToExpiry(int minutesToExpiry) {
54+
this.minutesToExpiry = minutesToExpiry;
55+
}
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package ca.bc.gov.open.bambora.payment.starter.managment;
2+
3+
import ca.bc.gov.open.bambora.payment.starter.managment.models.RecurringPaymentDetails;
4+
import com.sun.jndi.toolkit.url.Uri;
5+
6+
public interface BamboraCardService {
7+
Uri setupRecurringPayment(RecurringPaymentDetails recurringPaymentDetails);
8+
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package ca.bc.gov.open.bambora.payment.starter.managment;
2+
3+
import ca.bc.gov.open.bambora.payment.starter.BamboraConstants;
4+
import ca.bc.gov.open.bambora.payment.starter.BamboraException;
5+
import ca.bc.gov.open.bambora.payment.starter.BamboraProperties;
6+
import ca.bc.gov.open.bambora.payment.starter.managment.models.RecurringPaymentDetails;
7+
import com.sun.jndi.toolkit.url.Uri;
8+
import org.apache.commons.codec.digest.DigestUtils;
9+
10+
import java.net.MalformedURLException;
11+
import java.text.MessageFormat;
12+
import java.text.SimpleDateFormat;
13+
import java.util.Calendar;
14+
import java.util.Date;
15+
16+
public class BamboraCardServiceImpl implements BamboraCardService {
17+
18+
private final BamboraProperties bamboraProperties;
19+
20+
public BamboraCardServiceImpl(BamboraProperties bamboraProperties) {
21+
this.bamboraProperties = bamboraProperties;
22+
}
23+
24+
@Override
25+
public Uri setupRecurringPayment(RecurringPaymentDetails recurringPaymentDetails) {
26+
try {
27+
return buildRecurringPaymentUrl(recurringPaymentDetails);
28+
} catch (MalformedURLException e) {
29+
throw new BamboraException("Url construction failed", e.getCause());
30+
}
31+
}
32+
33+
34+
private Uri buildRecurringPaymentUrl(RecurringPaymentDetails recurringPaymentDetails) throws MalformedURLException {
35+
36+
String operationType = (recurringPaymentDetails.getEndUserId() != null ? BamboraConstants.OperationTypes.M.toString() : BamboraConstants.OperationTypes.N.toString());
37+
38+
StringBuilder paramString = new StringBuilder();
39+
40+
paramString.append(formatBamboraParam("", BamboraConstants.PARAM_PPRDIR_SERVICE_VERSION, bamboraProperties.getHostedProfileServiceVersion()));
41+
42+
paramString.append(formatBamboraParam("&", BamboraConstants.PARAM_PPRDIR_MERCHANT_ID, bamboraProperties.getMerchantId()));
43+
44+
paramString.append(formatBamboraParam("&", BamboraConstants.PARAM_PPRDIR_LANGUAGE, BamboraConstants.LANGUAGE_TYPE));
45+
46+
paramString.append(formatBamboraParam("&", BamboraConstants.PARAM_PPRDIR_OPERATION_TYPE, operationType));
47+
48+
paramString.append(formatBamboraParam("&", BamboraConstants.PARAM_PPRDIR_REF1, recurringPaymentDetails.getEchoData()));
49+
50+
paramString.append(formatBamboraParam("&", BamboraConstants.PARAM_PPRDIR_RETURN_URL, recurringPaymentDetails.getRedirectURL()));
51+
52+
paramString.append(formatBamboraParam("&", BamboraConstants.PARAM_PPRDIR_ORDER_NUMBER, recurringPaymentDetails.getRedirectURL()));
53+
54+
if (operationType.equals(BamboraConstants.OperationTypes.M.toString()))
55+
paramString.append(formatBamboraParam("&", BamboraConstants.PARAM_PPRDIR_CUSTOMER_CODE, recurringPaymentDetails.getEndUserId()));
56+
57+
paramString.append(MessageFormat.format("&{0}={1}&{2}={3}", BamboraConstants.PARAM_TRANS_HASH_VALUE, getHash(paramString.toString()), BamboraConstants.PARAM_TRANS_HASH_EXPIRY, getExpiry()));
58+
59+
return new Uri(MessageFormat.format("{0}?{1}", bamboraProperties.getHostedProfileUrl(), paramString.toString()));
60+
61+
}
62+
63+
private String getExpiry() {
64+
SimpleDateFormat sdfDate = new SimpleDateFormat(BamboraConstants.PARAM_TRANS_HASH_EXPIRY_FORMAT);
65+
Calendar cal = Calendar.getInstance();
66+
cal.setTime(new Date());
67+
cal.add(Calendar.MINUTE, bamboraProperties.getMinutesToExpiry());
68+
return sdfDate.format(cal.getTime());
69+
}
70+
71+
private String formatBamboraParam(String prefix, String key, String value) {
72+
return MessageFormat.format("{0}{1}={2}", prefix, key, value).replace(" ", "%20");
73+
}
74+
75+
private String getHash(String message) {
76+
String digest = DigestUtils.md5Hex(MessageFormat.format("{0}{1}", message, bamboraProperties.getHashKey()));
77+
return digest.toUpperCase();
78+
}
79+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package ca.bc.gov.open.bambora.payment.starter.managment.models;
2+
3+
public class RecurringPaymentDetails {
4+
private String orderNumber;
5+
private String endUserId;
6+
private String echoData;
7+
private String redirectURL;
8+
9+
public String getOrderNumber() {
10+
return orderNumber;
11+
}
12+
13+
public String getEndUserId() {
14+
return endUserId;
15+
}
16+
17+
public String getEchoData() {
18+
return echoData;
19+
}
20+
21+
public String getRedirectURL() {
22+
return redirectURL;
23+
}
24+
25+
protected RecurringPaymentDetails(Builder builder) {
26+
this.orderNumber = builder.orderNumber;
27+
this.endUserId = builder.endUserId;
28+
this.echoData = builder.echoData;
29+
this.redirectURL = builder.redirectURL;
30+
}
31+
32+
public static RecurringPaymentDetails.Builder builder() {
33+
return new RecurringPaymentDetails.Builder();
34+
}
35+
36+
public static class Builder {
37+
38+
private String orderNumber;
39+
private String endUserId;
40+
private String echoData;
41+
private String redirectURL;
42+
43+
public Builder orderNumber(String orderNumber) {
44+
this.orderNumber = orderNumber;
45+
return this;
46+
}
47+
48+
public Builder endUserId(String endUserId) {
49+
this.endUserId = endUserId;
50+
return this;
51+
}
52+
53+
public Builder echoData(String echoData) {
54+
this.echoData = echoData;
55+
return this;
56+
}
57+
58+
public Builder redirectURL(String redirectURL) {
59+
this.redirectURL = redirectURL;
60+
return this;
61+
}
62+
63+
public RecurringPaymentDetails create() {
64+
return new RecurringPaymentDetails(this);
65+
}
66+
67+
}
68+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2+
ca.bc.gov.open.bambora.payment.starter.AutoConfiguration

0 commit comments

Comments
 (0)